Browse code

Move video init and mouse logic to rayui.c/rayui.h . Move background loading to bg.c/bg.h

Dario Rodriguez authored on 20/09/2025 18:36:52
Showing 6 changed files
... ...
@@ -4,14 +4,16 @@ LDFLAGS=
4 4
 
5 5
 all: imgmover imgmover.exe
6 6
 
7
-imgmover: imgmover.c roboto_regular.c
8
-	$(CC) $(CFLAGS) -Iexternal/raylib/include/ imgmover.c external/raylib/libraylib.a -lm $(LDFLAGS) -o imgmover
7
+imgmover: imgmover.c roboto_regular.c bg.c bg.h rayui.c rayui.h
8
+	$(CC) $(CFLAGS) -Iexternal/raylib/include/ imgmover.c bg.c rayui.c external/raylib/libraylib.a -lm $(LDFLAGS) -o imgmover
9 9
 
10
-imgmover.exe: imgmover.c win32_pipe.c roboto_regular.c
10
+imgmover.exe: imgmover.c win32_pipe.c roboto_regular.c bg.c bg.h rayui.c rayui.h
11 11
 	sh -c "if [ ! -e test-icon_256x256.png ] ; then convert -size 256x256 xc:white test-icon_256x256.png ; fi"
12 12
 	toolchain-zig/compile.sh imgmover.c -c -o imgmover-windows.o
13 13
 	toolchain-zig/compile.sh win32_pipe.c -c -o win32_pipe-windows.o -Wno-missing-declarations
14
-	toolchain-zig/link.sh -icon test-icon_256x256.png imgmover.exe imgmover-windows.o win32_pipe-windows.o toolchain-zig/windows-msys2-mingw/lib/libraylib.a toolchain-zig/windows-msys2-mingw/lib/libpthread.a toolchain-zig/windows-msys2-mingw/lib/w32api/libuser32.a
14
+	toolchain-zig/compile.sh bg.c -c -o bg-windows.o -Wno-missing-declarations
15
+	toolchain-zig/compile.sh rayui.c -c -o rayui-windows.o -Wno-missing-declarations
16
+	toolchain-zig/link.sh -icon test-icon_256x256.png imgmover.exe imgmover-windows.o win32_pipe-windows.o bg-windows.o rayui-windows.o toolchain-zig/windows-msys2-mingw/lib/libraylib.a toolchain-zig/windows-msys2-mingw/lib/libpthread.a toolchain-zig/windows-msys2-mingw/lib/w32api/libuser32.a
15 17
 
16 18
 roboto_regular.c: ttf2h.sh fonts/Roboto-Regular.ttf
17 19
 	./ttf2h.sh fonts/Roboto-Regular.ttf
... ...
@@ -19,5 +21,5 @@ roboto_regular.c: ttf2h.sh fonts/Roboto-Regular.ttf
19 21
 roboto_regular.h: roboto_regular.c
20 22
 
21 23
 clean:
22
-	rm -f imgmover-windows.o win32_pipe-windows.o imgmover imgmover.exe
24
+	rm -f imgmover-windows.o win32_pipe-windows.o bg-windows.o rayui-windows.o imgmover imgmover.exe
23 25
 
24 26
new file mode 100644
... ...
@@ -0,0 +1,283 @@
1
+/*
2
+ * bg.c
3
+ *
4
+ * Wrapper over pthread with the addition of some interthread comms.
5
+ *
6
+ * History:
7
+ *      20250904 Creation from imgmover prototype.
8
+ *
9
+ * Author: Dario Rodriguez dario@darionomono.com
10
+ * (c) Dario Rodriguez 2025
11
+ * This program is licensed under the terms of GNU GPL v2.1+
12
+ */
13
+
14
+#include <stdio.h>
15
+#include <stdlib.h>
16
+#include <unistd.h>
17
+#include <string.h>
18
+#include <pthread.h>
19
+#if !defined(__linux__) && !defined(ANDROID)
20
+#include "win32_pipe.h"
21
+#endif
22
+
23
+#include "raylib.h"
24
+#include "rayui.h"
25
+#include "bg.h"
26
+
27
+static int mypipe(int fds[2]);
28
+static int mypiperead(int fd, char *buf, int count);
29
+static int mypipewrite(int fd, char *buf, int count);
30
+
31
+void
32
+bg_staticinit(void)
33
+{
34
+#if !defined(__linux__) && !defined(ANDROID)
35
+        win32pipe_init();
36
+#endif
37
+}
38
+
39
+void
40
+bg_staticfini(void)
41
+{
42
+#if !defined(__linux__) && !defined(ANDROID)
43
+        win32pipe_fini();
44
+#endif
45
+}
46
+
47
+bg_t *
48
+bg_init(int sizebgload)
49
+{
50
+        bg_t *bg;
51
+        char *errstr;
52
+        bg=NULL;
53
+        if((errstr="Insuf. mem. for bg")==NULL
54
+          || (bg=calloc(1,sizeof(bg_t)))==NULL
55
+          || (errstr="Error init pipes (please check program is not blocked in firewall)")==NULL
56
+          || (bg->pipe[0]=bg->pipe[1]=-1)!=-1
57
+          || mypipe(bg->pipe)!=0
58
+          || (errstr="Insuf mem bgload")==NULL
59
+          || (bg->bgload=calloc(sizebgload,sizeof(bgload_t)))==NULL
60
+          || (bg->sizebgload=sizebgload)!=sizebgload
61
+          || (errstr="pthread attr init error")==NULL
62
+          || pthread_attr_init(&(bg->tattr))!=0
63
+          || (errstr="pthread create error")==NULL
64
+          || pthread_create(&(bg->thread),&(bg->tattr),bg_thread,(void *)bg)!=0
65
+          || (bg->flag_threadstarted=1)!=1
66
+        ) {
67
+                global_messagebox("%s",errstr);
68
+                bg_free(bg);
69
+                return(NULL);
70
+        }
71
+        return(bg);
72
+}
73
+
74
+
75
+void
76
+bg_free(bg_t *bg)
77
+{
78
+        int i;
79
+        if(bg==NULL)
80
+                return; /* nothing to do */
81
+        if(bg->flag_threadstarted) {
82
+                char dummy=1;
83
+#if 1
84
+fprintf(stderr,"bg_free: notifying thread to exit\n");
85
+#endif
86
+                mypipewrite(bg->pipe[WR],&dummy,1);
87
+#if 1
88
+fprintf(stderr,"bg_free: joining thread\n");
89
+#endif
90
+                pthread_join(bg->thread,NULL);
91
+#if 1
92
+fprintf(stderr,"bg_free: thread joined OK\n");
93
+#endif
94
+                bg->flag_threadstarted=0;
95
+        }
96
+        if(bg->pipe[0]!=-1)
97
+                close(bg->pipe[0]),bg->pipe[0]=-1;
98
+        if(bg->pipe[1]!=-1)
99
+                close(bg->pipe[1]),bg->pipe[1]=-1;
100
+        if(bg->bgload!=NULL) {
101
+                bgload_t *bgload;
102
+                for(i=0,bgload=bg->bgload;i<bg->sizebgload;i++,bgload++) {
103
+                        if(bgload->has_data) {
104
+                                UnloadImage(bgload->image);
105
+                                bgload->has_data=0;
106
+                        }
107
+                }
108
+                free(bg->bgload),bg->bgload=NULL,bg->sizebgload=0;
109
+        }
110
+        return;
111
+}
112
+
113
+int
114
+bg_resetmarks(bg_t *bg)
115
+{
116
+        int i;
117
+        bgload_t *bgload;
118
+        if(bg==NULL)
119
+                return(-1);
120
+        for(i=0,bgload=bg->bgload;i<bg->sizebgload;i++,bgload++)
121
+                bgload->has_mark=0;
122
+        return(0);
123
+}
124
+
125
+bgload_t *
126
+bg_get(bg_t *bg, char *path)
127
+{
128
+        int i;
129
+        bgload_t *bgload;
130
+        if(bg==NULL)
131
+                return(NULL);
132
+        for(i=0,bgload=bg->bgload;i<bg->sizebgload;i++,bgload++) {
133
+                if(bgload->thread_finished && bgload->has_data && strcmp(path,bgload->path)==0) {
134
+                        bgload->has_mark=1;
135
+#if 1
136
+fprintf(stderr,"bg_get: \"%s\"\n",bgload->path);
137
+#endif
138
+                        return(bgload);
139
+                }
140
+        }
141
+        return(NULL);
142
+}
143
+
144
+int
145
+bg_add(bg_t *bg, char *path)
146
+{
147
+        int i;
148
+        bgload_t *bgload;
149
+        char dummy;
150
+        if(bg==NULL)
151
+                return(-1);
152
+        for(i=0,bgload=bg->bgload;i<bg->sizebgload;i++,bgload++) {
153
+                if(bgload->lended_to_thread && strcmp(path,bgload->path)==0) {
154
+                        bgload->is_todo=1;
155
+                        bgload->has_mark=1;
156
+                        dummy=0;
157
+                        mypipewrite(bg->pipe[WR],&dummy,1);
158
+                        return(0); /* already on list */
159
+                }
160
+        }
161
+        for(i=0,bgload=bg->bgload;i<bg->sizebgload;i++,bgload++) {
162
+                if(bgload->lended_to_thread==0) {
163
+                        memset(bgload,0,sizeof(bgload_t));
164
+                        strncpy(bgload->path,path,sizeof(bgload->path));
165
+                        bgload->path[sizeof(bgload->path)-1]='\0';
166
+                        bgload->is_todo=1;
167
+                        bgload->has_mark=1;
168
+                        dummy=0;
169
+                        bgload->lended_to_thread=1;
170
+                        mypipewrite(bg->pipe[WR],&dummy,1);
171
+                        return(0); /* added to list */
172
+                }
173
+        }
174
+        return(-1); /* couldn't add */
175
+}
176
+
177
+int
178
+bg_freeunmarked(bg_t *bg)
179
+{
180
+        int i;
181
+        bgload_t *bgload;
182
+        if(bg==NULL)
183
+                return(-1);
184
+        for(i=0,bgload=bg->bgload;i<bg->sizebgload;i++,bgload++) {
185
+                if(bgload->lended_to_thread && bgload->thread_finished && bgload->has_mark==0) {
186
+                        if(bgload->has_data) {
187
+#if 1
188
+fprintf(stderr,"bg: Unloading: \"%s\"\n",bgload->path);
189
+#endif
190
+                                UnloadImage(bgload->image);
191
+                                bgload->has_data=0;
192
+                        }
193
+#if 1
194
+else {
195
+fprintf(stderr,"bg: Cancelling: \"%s\"\n",bgload->path);
196
+}
197
+#endif
198
+                        memset(bgload,0,sizeof(bgload_t));
199
+                }
200
+        }
201
+        return(0);
202
+}
203
+
204
+void *
205
+bg_thread(void *parambg)
206
+{
207
+        bg_t *bg;
208
+        char dummy;
209
+        bg=(bg_t *)parambg;
210
+        int i;
211
+        bgload_t *bgload;
212
+        while(1) {
213
+                mypiperead(bg->pipe[RD],&dummy,1);
214
+#if 1
215
+fprintf(stderr,"Thread received byte: %i\n",(int)((unsigned char)dummy));
216
+#endif
217
+                if(dummy!=0)
218
+                        break; /* was told to exit */
219
+                for(i=0,bgload=bg->bgload;i<bg->sizebgload;i++,bgload++) {
220
+                        if(bgload->lended_to_thread==0)
221
+                                continue;
222
+                        if(bgload->is_todo==0) {
223
+                                bgload->thread_finished=1;
224
+                                continue;
225
+                        }
226
+                        if(bgload->has_data==0 && bgload->has_failedload==0) {
227
+                                bgload->image=global_loadimage(bgload->path);
228
+                                if(IsImageValid(bgload->image))
229
+                                        bgload->has_data=1;
230
+                                else
231
+                                        bgload->has_failedload=1;
232
+                                bgload->thread_finished=1;
233
+                        }
234
+                }
235
+        }
236
+        pthread_exit(NULL);
237
+        return(NULL);
238
+}
239
+
240
+
241
+
242
+#if !defined(__linux__) && !defined(ANDROID)
243
+static int
244
+mypipe(int fds[2])
245
+{
246
+        return(win32pipe_pipe(fds));
247
+}
248
+
249
+static int
250
+mypiperead(int fd, char *buf, int count)
251
+{
252
+        return(win32pipe_read(fd,buf,count));
253
+}
254
+
255
+static int
256
+mypipewrite(int fd, char *buf, int count)
257
+{
258
+        return(win32pipe_write(fd,buf,count));
259
+}
260
+#else
261
+static int
262
+mypipe(int fds[2])
263
+{
264
+        return(pipe(fds));
265
+}
266
+
267
+static int
268
+mypiperead(int fd, char *buf, int count)
269
+{
270
+        return(read(fd,buf,count));
271
+}
272
+
273
+static int
274
+mypipewrite(int fd, char *buf, int count)
275
+{
276
+        return(write(fd,buf,count));
277
+}
278
+#endif
279
+
280
+
281
+
282
+
283
+
0 284
new file mode 100644
... ...
@@ -0,0 +1,60 @@
1
+/*
2
+ * bg.c
3
+ *
4
+ * Wrapper over pthread with the addition of some interthread comms.
5
+ *
6
+ * HEADER FILE
7
+ *
8
+ * History:
9
+ *      20250904 Creation from imgmover prototype.
10
+ *
11
+ * Author: Dario Rodriguez dario@darionomono.com
12
+ * (c) Dario Rodriguez 2025
13
+ * This program is licensed under the terms of GNU GPL v2.1+
14
+ */
15
+
16
+#ifndef BG_H
17
+#define BG_H
18
+
19
+#include <pthread.h>
20
+#include "raylib.h"
21
+
22
+typedef struct bgload_t {
23
+        /* main/thread ownership management */
24
+        int lended_to_thread; // written from main, read from thread
25
+        int thread_finished; // written from thread, read from main
26
+        int is_todo;  // written from main, read from thread
27
+        int has_mark;  // written/read from main
28
+        /* data only accessed from owner */
29
+        char path[1024]; // to use only from owner
30
+        Image image; // to use only from owner
31
+        int has_data; // to use only from owner
32
+        int has_failedload; // to use only from owner
33
+} bgload_t;
34
+
35
+typedef struct bg_t {
36
+        int sizebgload;
37
+        bgload_t *bgload;
38
+        int pipe[2];
39
+        pthread_t thread;
40
+        pthread_attr_t tattr;
41
+        int flag_threadstarted;
42
+} bg_t;
43
+
44
+
45
+void bg_staticinit(void);
46
+void bg_staticfini(void);
47
+
48
+bg_t *bg_init(int sizebgload);
49
+void bg_free(bg_t *bg);
50
+int bg_resetmarks(bg_t *bg);
51
+bgload_t *bg_get(bg_t *bg, char *path);
52
+int bg_add(bg_t *bg, char *path);
53
+int bg_freeunmarked(bg_t *bg);
54
+
55
+void *bg_thread(void *);
56
+
57
+
58
+#endif
59
+
60
+
... ...
@@ -1,40 +1,11 @@
1 1
 /*
2 2
  * imgmover.c
3 3
  *
4
- * Simple C application using raylib to move images between directories.
4
+ * Simple C application using raylib to cselect/rotate/classify/arrange photos.
5 5
  *
6 6
  * History:
7
- *      20250119 Creation. Menu bar.
8
- *      20250123 Load font.
9
- *      20250213 Support sticky drop-down menus.
10
- *      20250216 Modularize menu handling.
11
- *      20250222 Able to list files.
12
- *      20250223 Draw pane titles and main dir list.
13
- *      20250224 Draw right dir list and store elem positions.
14
- *      20250225 Draw image placeholders
15
- *      20250226 Fix rightside positions
16
- *      20250228 Navigate directories
17
- *      20250301 Aesthetic fixes for leftside.
18
- *               Basic image loading.
19
- *               Show big image on hover.
20
- *               Preserve aspect ratio of big image.
21
- *      20250305 Scrollable left pane.
22
- *      20250308 Show statustooltip on image hover.
23
- *               Scrollwheel support for leftside.
24
- *               Fix thumb aspect ratio.
25
- *      20250311 Fix bug because of stray CloseWindow() call.
26
- *               Add show using all window with right button.
27
- *      20250316 Add android target support.
28
- *               Delay loading images if over fps deadline.
29
- *               Scroll by finger. Big image on double click.
30
- *      20250319 Add-dirdata button.
31
- *      20250320 Fix add-dirdata button appearance.
32
- *               Dirdata colors. Select dirdata.
33
- *      20250329 Background loading of thumbnails.
34
- *      20250330 Refine background loading.
35
- *      20250413 Background loading for windows target.
36
- *      20250420 Fix background loading for windows target.
37
- *      20250427 Start move image functionality.
7
+ *      20250902 Rewrite using parts of old prototype.
8
+ *      20250920 Reimplemented all scroll functionality.
38 9
  *
39 10
  * Author: Dario Rodriguez dario@darionomono.com
40 11
  * (c) Dario Rodriguez 2025
... ...
@@ -54,152 +25,32 @@
54 25
 #include "win32_pipe.h"
55 26
 #endif
56 27
 
57
-#include "raylib.h"
58
-#include "roboto_regular.c"
28
+#include "rayui.h"
29
+#include "bg.h"
59 30
 
60
-#define UTF8DOWNARROW "\xe2\x86\x86" /* U+2186 in UTF-8 */
61
-
62
-//#ifndef ANDROID
63
-//#define SIMANDROID
64
-//#endif
65
-
66
-#define TARGETFPS 30
67
-
68
-#if defined(ANDROID) || defined(SIMANDROID)
69
-#define ROOTDIR "/sdcard/"
70
-#define DEFAULTWIDTH 2400
71
-#define DEFAULTHEIGHT 1080
72
-#define LEFTSIZE 1600
73
-#define DEFAULTDIRDATAHEIGHT 492
74
-#define DEFAULTDIRDATATRIANGLEW 100
75
-#define LEFTIMAGESIDELEN 326
76
-#define FONTSIZE 64
77
-#define FONTBIGSIZE 96
78
-#define FONTHUGESIZE 128
79
-#define ADDREMOVEDIRDATAHEIGHT 128
80
-#else
81
-#if !defined(__linux__) && !defined(ANDROID)
82
-#define ROOTDIR "Z:\\"
83
-#define SEP "\\"
84
-#else
85
-//#define ROOTDIR "/var/www/default/animeshot/"
86
-#define ROOTDIR "/"
87
-#define SEP "/"
88
-#endif
89 31
 #define DEFAULTWIDTH 1280
90 32
 #define DEFAULTHEIGHT 768
91
-#define LEFTSIZE 720
92
-#define DEFAULTDIRDATAHEIGHT 150
93
-#define DEFAULTDIRDATATRIANGLEW 35
94
-#define LEFTIMAGESIDELEN 125
95
-#define FONTSIZE 18
96
-#define FONTBIGSIZE 32
97
-#define FONTHUGESIZE 48
98
-#define ADDREMOVEDIRDATAHEIGHT 128
99
-#endif
100
-
33
+#define LEFTIMAGESIDELEN 326
101 34
 #define SCROLLTHRESHOLD (LEFTIMAGESIDELEN/3)
102
-
103
-
104
-#if defined(SIMANDROID)
105
-#undef ROOTDIR
106
-#define ROOTDIR "/var/www/default/animeshot/"
107
-#endif
108
-
109 35
 #define WHEELSTEP LEFTIMAGESIDELEN
110
-
111
-
36
+#define SEP '/'
37
+#define SIZEBGLOAD 256
38
+#define DEFAULTDIRDATAHEIGHT 492
39
+#define ADDREMOVEDIRDATAHEIGHT 128
40
+#define UTF8DOWNARROW "\xe2\x86\x86" /* U+2186 in UTF-8 */
41
+#define DEFAULTDIRDATATRIANGLEW 35
112 42
 #define BLOCKLISTINGBUF 2048
113 43
 #define BLOCKLISTINGELEMS 1024
114 44
 #define BLOCKDIRDATA 16
115
-#define SIZEBGLOAD 256
116 45
 
117
-#ifndef FILLXY
118
-#define FILLXY(xywh,valx,valy) (xywh).x=(valx),(xywh).y=(valy)
119
-#endif
46
+#define MYFUNC "UNKNOWN"
47
+#define IMDEBUG(a) fprintf(stderr,"%s:%i: %s: %s\n",__FILE__,__LINE__,MYFUNC,a)
120 48
 
121
-#ifndef FILLWH
122
-#define FILLWH(xywh,valw,valh) (xywh).w=(valw),(xywh).h=(valh)
123
-#endif
124
-
125
-#ifndef FILLXYWH
126
-#define FILLXYWH(xywh,valx,valy,valw,valh) (xywh).x=(valx),(xywh).y=(valy),(xywh).w=(valw),(xywh).h=(valh)
127
-#endif
128
-
129
-#ifndef UNROLLXYWH
130
-#define UNROLLXYWH(xywh) (xywh).x,(xywh).y,(xywh).w,(xywh).h
131
-#endif
132
-
133
-#ifndef UNROLLWHXY
134
-#define UNROLLWHXY(xywh) (xywh).w,(xywh).h,(xywh).x,(xywh).y
135
-#endif
136
-
137
-#ifndef RD
138
-#define RD 0
139
-#endif
140
-
141
-#ifndef WR
142
-#define WR 1
143
-#endif
144
-
145
-#if !defined(__linux__) && !defined(ANDROID)
146
-int MessageBoxA(void *hWnd,void *lpText,void *lpCaption,unsigned int uType);
147
-#define messagebox(str) MessageBoxA(NULL,str,"imgmover",0);
148
-#else
149
-#define messagebox(str) fprintf(stderr,"%s\n",str);
150
-#endif
151
-
152
-
153
-
154
-#if !defined(__linux__) && !defined(ANDROID) && RAYLIB_VERSION_MAJOR==5 && RAYLIB_VERSION_MINOR==0
155
-/* the old raylib used in the windows build lacks this function */
156
-bool IsImageValid(Image image)
157
-{
158
-    bool result = false;
159
-
160
-    if ((image.data != NULL) &&     // Validate pixel data available
161
-        (image.width > 0) &&        // Validate image width
162
-        (image.height > 0) &&       // Validate image height
163
-        (image.format > 0) &&       // Validate image format
164
-        (image.mipmaps > 0)) result = true; // Validate image mipmaps (at least 1 for basic mipmap level)
165
-
166
-    return result;
167
-}
168
-#endif
169
-
170
-typedef struct xywh_t {
171
-        int x;
172
-        int y;
173
-        int w;
174
-        int h;
175
-} xywh_t;
176
-
177
-typedef struct font_t {
178
-        Font font;
179
-        int height;
180
-} font_t;
181
-
182
-typedef struct menudata_t {
183
-        char *title;
184
-        xywh_t xywh;
185
-        int sizeoptions;
186
-        char **options;
187
-        xywh_t optionsxywh;
188
-        int flag_open;
189
-        int flag_stickyopen;
190
-        int currentoption;
191
-} menudata_t;
192
-
193
-typedef struct menubar_t {
194
-        int height;
195
-        int sizemenudata;
196
-        menudata_t **menudata;
197
-        font_t *ptrfont;
198
-} menubar_t;
49
+// RIGHTSIDEMARGIN=FONTBIGSIZE/2
199 50
 
200 51
 typedef struct thumb_t {
201
-        xywh_t xywh;
202
-        xywh_t screenxywh;
52
+        whxy_t whxy;
53
+        whxy_t screenwhxy;
203 54
         Texture2D texture;
204 55
         int has_texture;
205 56
         int has_failedload;
... ...
@@ -218,9 +69,9 @@ typedef struct listing_t {
218 69
         int sizebuf;
219 70
         int usedbuf;
220 71
         char *buf;
221
-        int has_leftxywh;
222
-        int has_rightxywh;
223
-        xywh_t lastleftxywh;
72
+        int has_leftwhxy;
73
+        int has_rightwhxy;
74
+        whxy_t lastleftwhxy;
224 75
 } listing_t;
225 76
 
226 77
 typedef struct dirdata_t {
... ...
@@ -237,35 +88,14 @@ typedef struct texture_t {
237 88
         int textureh;
238 89
         int has_texture;
239 90
         int has_failedload;
240
-        xywh_t source; /* be able to detect a "double click" */
91
+        whxy_t source; /* be able to detect a "double click" */
241 92
 } texture_t;
242 93
 
243
-typedef struct bgload_t {
244
-        /* main/thread ownership management */
245
-        int lended_to_thread; // written from main, read from thread
246
-        int thread_finished; // written from thread, read from main
247
-        int is_todo;  // written from main, read from thread
248
-        int has_mark;  // written/read from main
249
-        /* data only accessed from owner */
250
-        char path[1024]; // to use only from owner
251
-        Image image; // to use only from owner
252
-        int has_data; // to use only from owner
253
-        int has_failedload; // to use only from owner
254
-} bgload_t;
255
-
256
-typedef struct bg_t {
257
-        int sizebgload;
258
-        bgload_t *bgload;
259
-        int pipe[2];
260
-        pthread_t thread;
261
-        pthread_attr_t tattr;
262
-        int flag_threadstarted;
263
-} bg_t;
264
-
265 94
 typedef struct body_t {
95
+        rayui_t *rayui;
266 96
         char *rootdir;
267
-        xywh_t xywh;
268
-        xywh_t backxywh;
97
+        whxy_t whxy;
98
+        whxy_t backwhxy;
269 99
         int leftsize;
270 100
         int sizedirdata;
271 101
         dirdata_t **dirdata;
... ...
@@ -278,223 +108,74 @@ typedef struct body_t {
278 108
         int is_displayingtexture;
279 109
         texture_t bigtexture;
280 110
         int flag_drawbigtexture;
281
-        xywh_t dirdataadd;
111
+        whxy_t dirdataadd;
282 112
         Font roundedbox;
283 113
         bg_t *bg;
284 114
         char selectedpath[2048];
285 115
 } body_t;
286 116
 
117
+
287 118
 typedef struct im_t {
288
-        int windowinit;
289
-        int w;
290
-        int h;
291
-        menubar_t *menubar;
119
+        rayui_t *rayui;
120
+        mousedata_t mousedata;
292 121
         body_t *body;
293
-        font_t *font;
294
-        font_t *fontbig;
295
-        font_t *fonthuge;
296 122
 } im_t;
297 123
 
298
-
299
-im_t *im_init(char *menus, char *rootdir);
124
+im_t *im_init(char *rootdir);
300 125
 void im_free(im_t *im);
301 126
 
302
-font_t *im_font_init(int size);
303
-void im_font_free(font_t *font);
304
-
305
-menubar_t *im_menubar_init(char *menus, font_t *font);
306
-void im_menubar_free(menubar_t *menubar);
307
-
308
-int im_menubar_mouse(menubar_t *menubar, Vector2 mousepos, int lmbpressed, int lmbreleased, int lmbdown, int *click_avail, char **sel_menu, char **sel_submenu);
309
-int im_menubar_draw(menubar_t *menubar, int windowwidth, int windowheight, int *needs_nextredraw);
310
-
311
-body_t *im_body_init(int x, int y, font_t *font, font_t *fontbig, font_t *fonthuge, int leftsize, char *rootdir, int windowwidth, int windowheight);
127
+body_t *im_body_init(rayui_t *rayui, int w, int h, int x, int y, int leftsidesize, char *rootdir);
312 128
 void im_body_free(body_t *body);
313 129
 
314 130
 int im_body_add(body_t *body,char *dir);
315 131
 int im_body_tryselect(body_t *body, Vector2 mousepos);
316 132
 
133
+int im_body_mouse(body_t *body, mousedata_t *mousedata);
134
+int im_body_draw(body_t *body, mousedata_t *mousedata, int windowwidth, int windowheight, int *needs_nextredraw);
317 135
 
318
-int im_body_mouse(body_t *body, Vector2 mousepos, Vector2 wheel, int lmbpressed, int lmbreleased, int lmbdown, int *click_avail);
319
-int im_body_draw(body_t *body, Vector2 mousepos, int lmbdown, int rmbdown, int windowwidth, int windowheight, int *needs_nextredraw, int scrollspeed);
320
-
136
+static int strptrcmp(void *a,void *b);
321 137
 int listing_get(listing_t *listing, char *pathprefix, char *path, int flag_sort);
322 138
 void listing_freedata(listing_t *listing);
323
-int listing_fillxywh(listing_t *listing, font_t *font, int w, int sidelen, int is_left);
139
+int listing_fillwhxy(listing_t *listing, font_t *font, int w, int sidelen, int is_left, int rightsidemargin);
140
+
141
+int is_imagefilename(char *filename);
324 142
 
325 143
 int texture_load(texture_t *texture, char *fullpath, int maxw, int maxh, bg_t *bg);
326 144
 int texture_draw(texture_t *texture, int x0, int y0, int maxw, int maxh);
327 145
 int texture_freedata(texture_t *texture);
328 146
 
329
-int imutil_menu_count(char *menus);
330
-char *imutil_menu_get(char *menus, int targetn, int *len);
331
-int imutil_submenu_count(char *menus);
332
-char *imutil_submenu_get(char *menus, int targetn, int *len);
333
-char *imutil_strduplen(char *str, int len);
334
-int is_imutil_insidexywh(Vector2 pos, xywh_t *xywh, int margin);
335 147
 int imutil_aspectmaximize(int w, int h, int maxw, int maxh, int *neww, int *newh);
336
-int menudata_pos2option(menudata_t *menudata, Vector2 pos);
337
-int *getcodepoints(int *sizecodepoints);
338
-int is_imagefilename(char *filename);
339
-Image imutil_loadimage(const char *filename);
340
-void imutil_fpsreset(void);
341
-int imutil_fpsleft(void);
342
-long long imutil_milliseconds(void);
343
-
344
-bg_t *bg_init(int sizebgload);
345
-void bg_free(bg_t *bg);
346
-int bg_resetmarks(bg_t *bg);
347
-bgload_t *bg_get(bg_t *bg, char *path);
348
-int bg_add(bg_t *bg, char *path);
349
-int bg_freeunmarked(bg_t *bg);
350 148
 
351
-void *bg_thread(void *);
352
-
353
-static int mypipe(int fds[2]);
354
-static int mypiperead(int fd, char *buf, int count);
355
-static int mypipewrite(int fd, char *buf, int count);
356 149
 
357 150
 int
358 151
 main(int argc, char *argv[])
359 152
 {
360 153
         im_t *im;
361
-        Vector2 mousepos,wheel,oldmousepos,scrollstartpos;
362
-        int flag_ignorelmb;
363
-        int lmbpressed,lmbreleased,lmbdown,rmbdown,oldlmbdown,oldrmbdown;
364
-        int click_avail;
365
-        int has_mousechanges;
154
+        char *rootdir;
366 155
         int needs_nextredraw;
367
-        long long scrollstart;
368
-        long long scrolllast;
369
-        int scrollspeed;
370
-        int is_scrolling;
371
-        int leftscrollposstart;
372
-        char *sel_menu,*sel_submenu;
373
-#if !defined(__linux__) && !defined(ANDROID)
374
-        win32pipe_init();
375
-#endif
376
-        if((im=im_init("Fichero\nAjustes\nSalir\n\nEditar\nNuevo directorio\n\nAyuda\nInformación sobre el programa\n\n",ROOTDIR))==NULL) {
377
-                messagebox("Couldn't init interface");
156
+        if(argc<2 || strcmp(argv[argc-1],"--help")==0) {
157
+                global_messagebox("imgmover\n\nSyntax: %s <rootdirectory>\n",(argc>0)?argv[0]:"imgmover");
158
+                return(1);
159
+        }
160
+        rootdir=argv[1];
161
+        bg_staticinit();
162
+        if((im=im_init(rootdir))==NULL) {
163
+                global_messagebox("%s","Couldn't init");
378 164
                 return(1);
379 165
         }
380
-        flag_ignorelmb=0;
381
-        mousepos=(Vector2) {.x=0,.y=0};
382
-        lmbdown=rmbdown=-1;
383
-        needs_nextredraw=1;
384
-        scrollstart=0;
385
-        is_scrolling=0;
386
-        im->body->selectedpath[0]='\0';
387 166
         while(!WindowShouldClose()) {
388
-                imutil_fpsreset();
389
-                oldmousepos=mousepos;
390
-                mousepos=GetMousePosition();
391
-                wheel=GetMouseWheelMoveV();
392
-                lmbpressed=IsMouseButtonPressed(0);
393
-                lmbreleased=IsMouseButtonReleased(0);
394
-                oldlmbdown=lmbdown;
395
-                lmbdown=IsMouseButtonDown(0);
396
-                oldrmbdown=rmbdown;
397
-                rmbdown=IsMouseButtonDown(1);
398
-                click_avail=1;
399
-                has_mousechanges=(lmbdown!=oldlmbdown || rmbdown!=oldrmbdown || mousepos.x!=oldmousepos.x || mousepos.y!=oldmousepos.y || wheel.x!=0 || wheel.y!=0)?1:0;
167
+                rayui_timereset(im->rayui);
400 168
                 needs_nextredraw=0;
401
-                /* mouse process scrolling */
402
-                if(lmbdown==1 && oldlmbdown==0 && scrollstart==0 && mousepos.y>im->body->xywh.y) {
403
-                        scrollstart=imutil_milliseconds();
404
-                        scrollstartpos=mousepos;
405
-                        leftscrollposstart=im->body->dirdata[im->body->currentdirdata]->leftscrollpos;
406
-                }
407
-                if(scrollstart!=0 && lmbdown==0) {
408
-                        scrollstart=0;
409
-                        if(is_scrolling)
410
-                                click_avail=0; /* this click is the mouseup of the scroll */
411
-                }
412
-                is_scrolling=(scrollstart==0)?0:is_scrolling;
413
-                if(is_scrolling==0 && scrollstart!=0) {
414
-                        float t;
415
-                        t=scrollstartpos.y-mousepos.y;
416
-                        t=(t<0)?-t:t;
417
-                        if(t>SCROLLTHRESHOLD) {
418
-                                is_scrolling=1;
419
-                                scrolllast=0;
420
-                        }
421
-                        t=scrollstartpos.x-mousepos.x;
422
-                        t=(t<0)?-t:t;
423
-                        if(t>SCROLLTHRESHOLD) {
424
-                                is_scrolling=0,scrollstart=0;
425
-                                im_body_tryselect(im->body,scrollstartpos);
426
-                                if(im->body->selectedpath[0]!='\0')
427
-                                        click_avail=0;
428
-                        }
429
-                }
430
-                if(is_scrolling) {
431
-                        long long tcur,tdif;
432
-                        long long ycur;
433
-                        tcur=imutil_milliseconds();
434
-                        tdif=tcur-scrolllast;
435
-                        ycur=scrollstartpos.y-mousepos.y;
436
-                        scrollspeed=(tdif>0)?(oldmousepos.y-mousepos.y)*100000/tdif:0;
437
-                        im->body->dirdata[im->body->currentdirdata]->leftscrollpos=leftscrollposstart+ycur;
438
-                        scrolllast=tcur;
439
-                }
440
-                if(is_scrolling==0 && scrollspeed!=0) {
441
-                        scrollspeed=scrollspeed*4/5;
442
-                        im->body->dirdata[im->body->currentdirdata]->leftscrollpos+=scrollspeed;
443
-                }
444
-                /* mouse process clicks on menus */
445
-                if(click_avail) {
446
-                        sel_menu=sel_submenu=NULL;
447
-                        im_menubar_mouse(im->menubar, mousepos, lmbpressed, lmbreleased, lmbdown, &click_avail, &sel_menu, &sel_submenu);
448
-                        if(sel_menu!=NULL && sel_submenu!=NULL) {
449
-
450
-#if 1
451
-fprintf(stderr,"SELECTED: \"%s\"->\"%s\"\n",sel_menu,sel_submenu);
452
-#endif
453
-                                if(strcmp(sel_submenu,"Salir")==0)
454
-                                        break; /* exit from main loop */
455
-                        }
456
-                }
457
-                if(click_avail)
458
-                        im_body_mouse(im->body, mousepos, wheel, lmbpressed, lmbreleased, lmbdown, &click_avail);
169
+                rayui_getmousedata(im->rayui,&(im->mousedata));
170
+                /* process mouse actions */
171
+                if(im->mousedata.click_avail)
172
+                        im_body_mouse(im->body, &(im->mousedata));
459 173
                 /* draw screen contents */
460 174
                 BeginDrawing();
461 175
                 ClearBackground(RAYWHITE);
462
-                im_body_draw(im->body,mousepos,lmbdown,rmbdown,im->w,im->h,&needs_nextredraw,scrollspeed);
463
-                im_menubar_draw(im->menubar,im->w,im->h,&needs_nextredraw);
464
-#if 0
465
-{
466
- int i,j;
467
- Vector2 v2;
468
- listing_t listing={0};
469
- if(listing_get(&listing,"..",".",1)==0) {
470
-   i=2;
471
-     v2.x=(float) (im->font->height/2);
472
-     v2.y=(float) ((im->font->height+im->font->height/2)*i+(im->font->height/4));
473
-     DrawTextEx(im->font->font
474
-       ,SEP
475
-       ,v2
476
-       ,im->font->height
477
-       ,0
478
-       ,((Color){ 45, 45, 45, 255 })
479
-     );
480
-   for(j=0;j<listing.usedelems;j++) {
481
-     Color c;
482
-     i++;
483
-     c=((Color){ 45, 45, 45, 255 });
484
-     v2.x=(float) (im->font->height/2);
485
-     v2.y=(float) ((im->font->height+im->font->height/2)*i+(im->font->height/4));
486
-     DrawTextEx(im->font->font
487
-       ,listing.elems[j].name
488
-       ,v2
489
-       ,im->font->height
490
-       ,0
491
-       ,c
492
-     );
493
-   }
494
- }
495
-}
496
-#endif
497
-                if(has_mousechanges==0 && needs_nextredraw==0 && scrollspeed==0) {
176
+                rayui_scrollablerectreset(im->rayui,&(im->mousedata));
177
+                im_body_draw(im->body,&(im->mousedata),im->rayui->w,im->rayui->h,&needs_nextredraw);
178
+                if(needs_nextredraw==0 && im->mousedata.has_mousechanges==0 && im->mousedata.scrollspeed==0) {
498 179
                         /* Wait for new events when calling EndDrawing() */
499 180
                         EnableEventWaiting();
500 181
                 } else {
... ...
@@ -504,39 +185,26 @@ fprintf(stderr,"SELECTED: \"%s\"->\"%s\"\n",sel_menu,sel_submenu);
504 185
                 EndDrawing();
505 186
         }
506 187
         im_free(im),im=NULL;
507
-#if !defined(__linux__) && !defined(ANDROID)
508
-        win32pipe_fini();
509
-#endif
188
+        bg_staticfini();
510 189
         return(0);
511 190
 }
512 191
 
192
+
513 193
 im_t *
514
-im_init(char *menus, char *rootdir)
194
+im_init(char *rootdir)
515 195
 {
516 196
         im_t *im;
517 197
         char *errstr;
518
-        if(menus==NULL)
519
-                return(NULL); /* sanity check failed */
520 198
         if((im=calloc(1,sizeof(im_t)))==NULL) {
521 199
                 im_free(im),im=NULL;
522 200
                 return(NULL); /* insuf. mem. */
523 201
         }
524
-        /* init window */
525
-        SetTraceLogLevel(LOG_ERROR);
526
-        InitWindow((im->w=DEFAULTWIDTH),(im->h=DEFAULTHEIGHT),"Image Mover");
527
-        im->windowinit=1;
528
-        SetTargetFPS(30);
529
-        /* init fonts and contents */
530
-        if((errstr="Couldn't init font")==NULL
531
-          || (im->font=im_font_init(FONTSIZE))==NULL
532
-          || (im->fontbig=im_font_init(FONTBIGSIZE))==NULL
533
-          || (im->fonthuge=im_font_init(FONTHUGESIZE))==NULL
534
-          || (errstr="Couldn't init menus")==NULL
535
-          || (im->menubar=im_menubar_init(menus,im->font))==NULL
202
+        if((errstr="init interface")==NULL
203
+          || (im->rayui=rayui_init(DEFAULTWIDTH,DEFAULTHEIGHT,"Image Mover",NULL))==NULL
536 204
           || (errstr="Couldn't init interface data")==NULL
537
-          || (im->body=im_body_init(0,im->menubar->height, im->font, im->fontbig, im->fonthuge, LEFTSIZE, rootdir,im->w,im->h))==NULL
205
+          || (im->body=im_body_init(im->rayui,im->rayui->w,im->rayui->h, 0, 0, im->rayui->w*2/3, rootdir))==NULL
538 206
         ) {
539
-                messagebox(errstr);
207
+                global_messagebox("Couldn't %s",errstr);
540 208
                 im_free(im),im=NULL;
541 209
                 return(NULL); /* insuf. mem. */
542 210
         }
... ...
@@ -550,299 +218,21 @@ im_free(im_t *im)
550 218
 {
551 219
         if(im==NULL)
552 220
                 return;
553
-        if(im->menubar!=NULL)
554
-                im_menubar_free(im->menubar),im->menubar=NULL;
555 221
         if(im->body!=NULL)
556 222
                 im_body_free(im->body),im->body=NULL;
557
-        if(im->font!=NULL)
558
-                im_font_free(im->font),im->font=NULL;
559
-        if(im->fontbig!=NULL)
560
-                im_font_free(im->fontbig),im->fontbig=NULL;
561
-        if(im->fonthuge!=NULL)
562
-                im_font_free(im->fonthuge),im->fonthuge=NULL;
563
-        if(im->windowinit)
564
-                CloseWindow(),im->windowinit=0;
223
+        if(im->rayui!=NULL)
224
+                rayui_free(im->rayui),im->rayui=NULL;
565 225
         free(im),im=NULL;
566
-        return;
567
-}
568
-
569
-font_t *
570
-im_font_init(int size)
571
-{
572
-        font_t *font;
573
-        int sizecodepoints;
574
-        int *codepoints;
575
-        if((font=calloc(1,sizeof(font_t)))==NULL)
576
-                return(NULL); /* insuf. mem. */
577
-        font->height=size;
578
-        codepoints=getcodepoints(&sizecodepoints);
579
-        font->font=LoadFontFromMemory(".ttf",(const unsigned char *)roboto_regular,sizeof(roboto_regular)-1,font->height,codepoints,sizecodepoints);
580
-        return(font);
581
-}
582
-
583
-void
584
-im_font_free(font_t *font)
585
-{
586
-        if(font==NULL)
587
-                return;
588
-        /* NOTE: Cannot call UnloadFont(font->font) as the data was not malloc'd; see https://github.com/raysan5/raylib/blob/master/examples/others/embedded_files_loading.c */
589
-        free(font),font=NULL;
590
-        return;
591
-}
592
-
593
-menubar_t *
594
-im_menubar_init(char *menus, font_t *font)
595
-{
596
-        int i,j;
597
-        char *str,*substr;
598
-        int len,sublen;
599
-        menubar_t *menubar;
600
-        menudata_t *menudata;
601
-        if(menus==NULL || font==NULL)
602
-                return(NULL); /* sanity check failed */
603
-        if((menubar=calloc(1,sizeof(menubar_t)))==NULL
604
-          || (menubar->sizemenudata=imutil_menu_count(menus))<=0
605
-          || (menubar->menudata=calloc(menubar->sizemenudata,sizeof(menudata_t)))==NULL
606
-        ) {
607
-                im_menubar_free(menubar),menubar=NULL;
608
-                return(NULL); /* insuf. mem. */
609
-        }
610
-        menubar->ptrfont=font;
611
-        menubar->height=font->height+font->height/2;
612
-        /* init menus */
613
-        for(i=0;i<menubar->sizemenudata;i++) {
614
-                if((menudata=menubar->menudata[i]=calloc(1,sizeof(menudata_t)))==NULL
615
-                  || (str=imutil_menu_get(menus,i,&len))==NULL
616
-                  || (menudata->title=imutil_strduplen(str,len))==NULL
617
-                  || (menudata->sizeoptions=imutil_submenu_count(str))<=0
618
-                  || (menudata->options=calloc(menudata->sizeoptions,sizeof(char *)))==NULL
619
-                ) {
620
-                        im_menubar_free(menubar),menubar=NULL;
621
-                        return(NULL); /* insuf. mem. */
622
-                }
623
-                for(j=0;j<menudata->sizeoptions;j++) {
624
-                        if((substr=imutil_submenu_get(str,j,&sublen))==NULL
625
-                          || (menudata->options[j]=imutil_strduplen(substr,sublen))==NULL
626
-                        ) {
627
-                                im_menubar_free(menubar),menubar=NULL;
628
-                                return(NULL); /* insuf. mem. */
629
-                        }
630
-                }
631
-        }
632
-#if 0
633
-        /* test imutil_menu_xxx */
634
-        int n,m,l,ml,len,mlen;
635
-        char *ptr,*mptr;
636
-        for(n=0,l=imutil_menu_count(menus);n<l;n++) {
637
-                ptr=imutil_menu_get(menus,n,&len);
638
-                fprintf(stderr,"menu[%i]:\"",n);
639
-                fwrite(ptr,1,len,stderr);
640
-                fprintf(stderr,"\"->");
641
-                for(m=0,ml=imutil_submenu_count(ptr);m<ml;m++) {
642
-                        mptr=imutil_submenu_get(ptr,m,&mlen);
643
-                        fprintf(stderr,"|\"");
644
-                        fwrite(mptr,1,mlen,stderr);
645
-                        fprintf(stderr,"\"");
646
-                }
647
-                fprintf(stderr,"\n");
648
-        }
649
-#endif
650
-#if 0
651
-        /* test menudata */
652
-        for(i=0;i<menubar->sizemenudata;i++) {
653
-                fprintf(stderr,"menu[%i]:\"%s\"->",i,menubar->menudata[i]->title);
654
-                for(j=0;j<menubar->menudata[i]->sizeoptions;j++)
655
-                        fprintf(stderr,"|\"%s\"",menubar->menudata[i]->options[j]);
656
-                fprintf(stderr,"\n");
657
-        }
658
-#endif
659
-        return(menubar);
660
-}
661
-
662
-void
663
-im_menubar_free(menubar_t *menubar)
664
-{
665
-        int i,j;
666
-        menudata_t *menudata;
667
-        if(menubar==NULL)
668
-                return;
669
-        if(menubar->menudata!=NULL) {
670
-                for(i=0;i<menubar->sizemenudata;i++) {
671
-                        if((menudata=menubar->menudata[i])==NULL)
672
-                                continue;
673
-                        if(menudata->title!=NULL)
674
-                                free(menudata->title),menudata->title=NULL;
675
-                        if(menudata->options!=NULL) {
676
-                                for(j=0;j<menudata->sizeoptions;j++) {
677
-                                        if(menudata->options[j]!=NULL)
678
-                                                free(menudata->options[j]),menudata->options[j]=NULL;
679
-                                }
680
-                                free(menudata->options),menudata->options=NULL,menudata->sizeoptions=0;
681
-                        }
682
-                        free(menubar->menudata[i]),menubar->menudata[i]=NULL,menudata=NULL;
683
-                }
684
-                free(menubar->menudata),menubar->menudata=NULL,menubar->sizemenudata=0;
685
-        }
686
-        free(menubar),menubar=NULL;
687
-        return;
688
-}
689
-
690
-int
691
-im_menubar_mouse(menubar_t *menubar, Vector2 mousepos, int lmbpressed, int lmbreleased, int lmbdown, int *click_avail, char **sel_menu, char **sel_submenu)
692
-{
693
-        int flag_outsideall;
694
-        int i,j;
695
-        if(menubar==NULL || click_avail==NULL || sel_menu==NULL || sel_submenu==NULL)
696
-                return(-1);
697
-        *click_avail=1;
698
-        *sel_menu=NULL;
699
-        *sel_submenu=NULL;
700
-        flag_outsideall=1;
701
-#if 0
702
-if(lmbpressed || lmbdown)
703
- fprintf(stderr,"in_menubar_mouse: lmbpressed:%i lmbdown:%i\n",lmbpressed,lmbdown);
704
-#endif
705
-        for(i=0;i<menubar->sizemenudata;i++) {
706
-                int insidetitle,currentoption;
707
-                insidetitle=is_imutil_insidexywh(mousepos,&(menubar->menudata[i]->xywh),0);
708
-                currentoption=menudata_pos2option(menubar->menudata[i],mousepos);
709
-                flag_outsideall=(currentoption!=-1 || insidetitle)?0:flag_outsideall;
710
-                if(lmbreleased && insidetitle) {
711
-                        for(j=0;j<menubar->sizemenudata;j++) {
712
-                                menubar->menudata[j]->flag_stickyopen=(j==i)?1:0;
713
-                                menubar->menudata[j]->flag_open=0;
714
-                                menubar->menudata[j]->currentoption=-1;
715
-                        }
716
-                } else if((lmbpressed || lmbdown) && insidetitle) {
717
-                        for(j=0;j<menubar->sizemenudata;j++) {
718
-                                menubar->menudata[j]->flag_open=(j==i)?1:0;
719
-                                menubar->menudata[j]->flag_stickyopen=0;
720
-                                menubar->menudata[j]->currentoption=-1;
721
-                        }
722
-                } else if((lmbdown || menubar->menudata[i]->flag_stickyopen) && currentoption!=-1) {
723
-                        for(j=0;j<menubar->sizemenudata;j++) {
724
-                                if(lmbreleased==0 || j!=i || menubar->menudata[i]->flag_stickyopen==0) {
725
-                                        menubar->menudata[j]->flag_open=(j==i)?menubar->menudata[i]->flag_open:0;
726
-                                        menubar->menudata[j]->flag_stickyopen=(j==i)?menubar->menudata[i]->flag_stickyopen:0;
727
-                                        menubar->menudata[j]->currentoption=(j==i)?currentoption:-1;
728
-                                } else {
729
-                                        menubar->menudata[j]->flag_open=0;
730
-                                        menubar->menudata[j]->flag_stickyopen=0;
731
-                                        menubar->menudata[j]->currentoption=-1;
732
-                                        /* has selected this submenu */
733
-                                        *click_avail=0;
734
-                                        *sel_menu=menubar->menudata[j]->title;
735
-                                        *sel_submenu=menubar->menudata[j]->options[currentoption];
736
-                                }
737
-                        }
738
-                } else if(menubar->menudata[i]->flag_stickyopen && currentoption==-1) {
739
-                        if(lmbreleased) {
740
-                                menubar->menudata[i]->flag_open=0;
741
-                                menubar->menudata[i]->flag_stickyopen=0;
742
-                        }
743
-                        menubar->menudata[i]->currentoption=-1;
744
-                } else if(lmbreleased && currentoption!=-1) {
745
-                        for(j=0;j<menubar->sizemenudata;j++) {
746
-                                menubar->menudata[j]->flag_open=0;
747
-                                menubar->menudata[j]->flag_stickyopen=0;
748
-                                menubar->menudata[j]->currentoption=-1;
749
-                        }
750
-                        /* has selected this submenu */
751
-                        *click_avail=0;
752
-                        *sel_menu=menubar->menudata[i]->title;
753
-                        *sel_submenu=menubar->menudata[i]->options[currentoption];
754
-                } else if(lmbdown==0) {
755
-                        menubar->menudata[i]->flag_open=0;
756
-                        menubar->menudata[i]->flag_stickyopen=0;
757
-                        menubar->menudata[i]->currentoption=-1;
758
-                }
759
-        }
760
-        if(flag_outsideall) {
761
-                for(j=0;j<menubar->sizemenudata;j++) {
762
-                        menubar->menudata[j]->currentoption=-1;
763
-                }
764
-        }
765
-        /* update click_avail */
766
-        for(j=0;j<menubar->sizemenudata;j++) {
767
-                if(menubar->menudata[j]->flag_open || menubar->menudata[j]->flag_stickyopen) {
768
-                        *click_avail=0;
769
-                        break;
770
-                }
771
-        }
772
-        return(0);
773
-}
774
-
775
-int
776
-im_menubar_draw(menubar_t *menubar, int windowwidth, int windowheight, int *needs_nextredraw)
777
-{
778
-        int i,j,k,x;
779
-        menudata_t *menudata;
780
-        font_t *font;
781
-        if(menubar==NULL)
782
-                return(-1); /* sanity check failed */
783
-        font=menubar->ptrfont;
784
-        DrawRectangle(0,0,windowwidth, font->height+font->height/2, (Color){ 235, 235, 235, 235 } );
785
-        for(i=0,x=0;i<menubar->sizemenudata;i++) {
786
-                Vector2 v2;
787
-                menudata=menubar->menudata[i];
788
-                v2=MeasureTextEx(font->font,menudata->title,font->height,0);
789
-                FILLXYWH(menudata->xywh,x,0,((int)v2.x)+font->height,font->height+font->height/2);
790
-                v2.x=(float) (menudata->xywh.x+font->height/2);
791
-                v2.y=(float) (menudata->xywh.y+font->height/4);
792
-                DrawTextEx(font->font
793
-                  ,menudata->title
794
-                  ,v2
795
-                  ,font->height
796
-                  ,0
797
-                  ,(Color){ 45, 45, 45, 255 }
798
-                );
799
-                if(menudata->flag_open || menudata->flag_stickyopen) {
800
-                        int underline_height=3;
801
-                        int maxw;
802
-                        DrawRectangle(menudata->xywh.x,menudata->xywh.y+menudata->xywh.h-underline_height,menudata->xywh.w,underline_height, (Color){ 53,132,228,255 } );
803
-                        for(j=0,maxw=0;j<menudata->sizeoptions;j++) {
804
-                                v2=MeasureTextEx(font->font,menudata->options[j],font->height,0);
805
-                                maxw=(((int)(v2.x))>maxw)?((int)(v2.x)):maxw;
806
-                        }
807
-                        maxw=(maxw<(menudata->xywh.w+font->height))?(menudata->xywh.w+font->height):maxw;
808
-                        maxw+=font->height;
809
-                        FILLXYWH(menudata->optionsxywh,menudata->xywh.x+1,menudata->xywh.y+menudata->xywh.h+2,maxw,(font->height+font->height/2)*menudata->sizeoptions);
810
-                        DrawLine(menudata->optionsxywh.x-1,menudata->optionsxywh.y-2,menudata->optionsxywh.x+menudata->optionsxywh.w+2,menudata->optionsxywh.y-2,(Color){ 255,255,255,255 } );
811
-                        DrawLine(menudata->optionsxywh.x-1,menudata->optionsxywh.y,menudata->optionsxywh.x-1,menudata->optionsxywh.y+menudata->optionsxywh.h+1,(Color){ 255,255,255,255 } );
812
-                        DrawLine(menudata->optionsxywh.x+menudata->optionsxywh.w+2,menudata->optionsxywh.y,menudata->optionsxywh.x+menudata->optionsxywh.w+2,menudata->optionsxywh.y+menudata->optionsxywh.h+1,(Color){ 192,192,192,255 } );
813
-                        DrawLine(menudata->optionsxywh.x-1,menudata->optionsxywh.y+menudata->optionsxywh.h+1,menudata->optionsxywh.x+menudata->optionsxywh.w+2,menudata->optionsxywh.y+menudata->optionsxywh.h+1,(Color){ 192,192,192,255 } );
814
-                        DrawRectangle(menudata->optionsxywh.x,menudata->optionsxywh.y,menudata->optionsxywh.w,menudata->optionsxywh.h,(Color){ 235, 235, 235, 235 });
815
-                        for(k=0;k<menudata->sizeoptions;k++) {
816
-                                Color c;
817
-                                c=(k==menudata->currentoption)?((Color){ 255,255,255,255 }):((Color){ 45, 45, 45, 255 });
818
-                                if(k==menudata->currentoption)
819
-                                        DrawRectangle(menudata->optionsxywh.x+1,menudata->optionsxywh.y+(font->height+(font->height/2))*k,menudata->optionsxywh.w-2,font->height+font->height/2,(Color){ 53,132,228,255 });
820
-                                v2.x=(float) (menudata->optionsxywh.x+font->height/2);
821
-                                v2.y=(float) (menudata->optionsxywh.y+(font->height/4)+(font->height+(font->height/2))*k);
822
-                                DrawTextEx(font->font
823
-                                  ,menudata->options[k]
824
-                                  ,v2
825
-                                  ,font->height
826
-                                  ,0
827
-                                  ,c
828
-                                );
829
-                        }
830
-                } else {
831
-                        FILLXYWH(menudata->optionsxywh,0,0,0,0);
832
-                }
833
-                x=menudata->xywh.x+menudata->xywh.w;
834
-        }
835
-        return(0);
836 226
 }
837 227
 
838 228
 body_t *
839
-im_body_init(int x, int y, font_t *font, font_t *fontbig, font_t *fonthuge, int leftsize, char *rootdir, int windowwidth, int windowheight)
229
+im_body_init(rayui_t *rayui, int w, int h, int x, int y, int leftsidesize, char *rootdir)
840 230
 {
841 231
         body_t *body;
842 232
         char *errstr;
843
-        static char sep[]={SEP};
844
-        if(font==NULL || fontbig==NULL || fonthuge==NULL || rootdir==NULL) {
845
-                messagebox("im_body_init sanity check failed");
233
+        static char sep[]={SEP,'\0'};
234
+        if(rayui->font==NULL || rayui->fontbig==NULL || rayui->fonthuge==NULL || rootdir==NULL) {
235
+                global_messagebox("im_body_init sanity check failed");
846 236
                 return(NULL); /* sanity check failed */
847 237
         }
848 238
         if((errstr="Insuf. mem. for body")==NULL
... ...
@@ -852,21 +242,25 @@ im_body_init(int x, int y, font_t *font, font_t *fontbig, font_t *fonthuge, int
852 242
           || (errstr="Error init bg")==NULL
853 243
           || (body->bg=bg_init(SIZEBGLOAD))==NULL
854 244
         ) {
855
-                messagebox(errstr);
245
+                global_messagebox("%s",errstr);
856 246
                 im_body_free(body),body=NULL;
857 247
                 return(NULL);
858 248
         }
859
-        FILLXYWH(body->xywh,x,y,windowwidth-x,windowheight-y);
860
-        body->leftsize=leftsize;
861
-        body->ptrfont=font;
862
-        body->ptrfontbig=fontbig;
863
-        body->ptrfonthuge=fonthuge;
864
-        if(body->rootdir[0]!='\0' && strcmp(body->rootdir,SEP)!=0 && body->rootdir[strlen(body->rootdir)-1]==sep[0])
249
+        body->rayui=rayui;
250
+        FILLWHXY(body->whxy,w,h,x,y);
251
+#if 1
252
+fprintf(stderr,"im_body_init: %ix%i+%i+%i\n",UNROLLWHXY(body->whxy));
253
+#endif
254
+        body->leftsize=leftsidesize;
255
+        body->ptrfont=rayui->font;
256
+        body->ptrfontbig=rayui->fontbig;
257
+        body->ptrfonthuge=rayui->fonthuge;
258
+        if(body->rootdir[0]!='\0' && strcmp(body->rootdir,sep)!=0 && body->rootdir[strlen(body->rootdir)-1]==sep[0])
865 259
                 body->rootdir[strlen(body->rootdir)-1]='\0'; /* rootdir doesn't need the final '/' */
866 260
         /* init rounded box glyph (a really big zero) */
867 261
         {
868 262
                 int codepoints[]={'O','+','-'};
869
-                body->roundedbox=LoadFontFromMemory(".ttf",(const unsigned char *)roboto_regular,sizeof(roboto_regular)-1,ADDREMOVEDIRDATAHEIGHT*4,codepoints,sizeof(codepoints)/sizeof(codepoints[0]));
263
+                body->roundedbox=LoadFontFromMemory(".ttf",rayui->defaultfontdata,rayui->sizedefaultfontdata,ADDREMOVEDIRDATAHEIGHT*4,codepoints,sizeof(codepoints)/sizeof(codepoints[0]));
870 264
         }
871 265
         return(body);
872 266
 }
... ...
@@ -942,12 +336,12 @@ im_body_tryselect(body_t *body, Vector2 mousepos)
942 336
         if(body==NULL || body->currentdirdata<0 || body->currentdirdata>=body->sizedirdata || body->dirdata[body->currentdirdata]==NULL || body->currentdirdata>=body->sizedirdata)
943 337
                 return(-1); /* sanity check failed */
944 338
         body->selectedpath[0]='\0';
945
-        if(!is_imutil_insidexywh(mousepos,&(body->xywh),0) || mousepos.x>body->leftsize)
339
+        if(!is_global_insidewhxy(mousepos,&(body->whxy),0) || mousepos.x>body->leftsize)
946 340
                 return(-1); /* outside leftside */
947 341
         listing=&(body->dirdata[body->currentdirdata]->listing);
948 342
         for(i=0;i<listing->usedelems;i++) {
949 343
                 elem=listing->elems+i;
950
-                if(is_imutil_insidexywh(mousepos,&(elem->left.screenxywh),0)) {
344
+                if(is_global_insidewhxy(mousepos,&(elem->left.screenwhxy),0)) {
951 345
                         strncpy(body->selectedpath,elem->name,sizeof(body->selectedpath));
952 346
                         body->selectedpath[sizeof(body->selectedpath)-1]='\0';
953 347
                         return(0); /* found */
... ...
@@ -956,39 +350,40 @@ im_body_tryselect(body_t *body, Vector2 mousepos)
956 350
         return(-1); /* no thumbnail found for pos */
957 351
 }
958 352
 
959
-
960 353
 int
961
-im_body_mouse(body_t *body, Vector2 mousepos, Vector2 wheel, int lmbpressed, int lmbreleased, int lmbdown, int *click_avail)
354
+im_body_mouse(body_t *body, mousedata_t *mousedata)
962 355
 {
963 356
         int i;
964 357
         char *ptr;
965 358
         dirdata_t *dirdata;
966 359
         listingdata_t *ld;
967 360
         int margin;
968
-        if(body==NULL || click_avail==NULL || body->currentdirdata<0 || body->currentdirdata>=body->sizedirdata || body->dirdata[body->currentdirdata]==NULL)
361
+        if(body==NULL || mousedata==NULL || body->currentdirdata<0 || body->currentdirdata>=body->sizedirdata || body->dirdata[body->currentdirdata]==NULL)
969 362
                 return(-1); /* sanity check error */
970 363
         dirdata=body->dirdata[body->currentdirdata];
971 364
         /* wheel */
972
-        body->dirdata[body->currentdirdata]->leftscrollpos-=(int)wheel.y*WHEELSTEP;
365
+        body->dirdata[body->currentdirdata]->leftscrollpos-=(int)mousedata->wheel.y*WHEELSTEP;
366
+        if(is_rayui_scrolling(body->rayui,mousedata,"body.leftside",&(body->dirdata[body->currentdirdata]->leftscrollpos)))
367
+                fprintf(stderr,"SCROLLING bosy.leftside newscrollpos:%i\n",body->dirdata[body->currentdirdata]->leftscrollpos); /* nothing to do, will fix coors for both wheel and scrolling in the next lines */
973 368
         body->dirdata[body->currentdirdata]->leftscrollpos=(body->dirdata[body->currentdirdata]->leftscrollpos<0)?0:body->dirdata[body->currentdirdata]->leftscrollpos;
974
-        if(body->dirdata[body->currentdirdata]->leftscrollpos>dirdata->listing.lastleftxywh.y)
975
-                body->dirdata[body->currentdirdata]->leftscrollpos=dirdata->listing.lastleftxywh.y;
369
+        if(body->dirdata[body->currentdirdata]->leftscrollpos>dirdata->listing.lastleftwhxy.y)
370
+                body->dirdata[body->currentdirdata]->leftscrollpos=dirdata->listing.lastleftwhxy.y;
976 371
         /* check if we have to process a click */
977
-        if(*click_avail==0 || lmbreleased==0)
372
+        if(mousedata->click_avail==0 || mousedata->lmbreleased==0)
978 373
                 return(0); /* nothing else to do */
979 374
         /* show image in full screen */
980 375
         if(body->flag_drawbigtexture) {
981
-                if(lmbreleased)
376
+                if(mousedata->lmbreleased)
982 377
                         body->flag_drawbigtexture=0;
983 378
                 return(0); /* nothing else to do */
984 379
         }
985 380
         margin=body->ptrfont->height/4;
986
-        if(body->is_displayingtexture && lmbreleased && is_imutil_insidexywh(mousepos,&(body->texture.source),margin) && body->selectedpath[0]=='\0') {
381
+        if(body->is_displayingtexture && mousedata->lmbreleased && is_global_insidewhxy(mousedata->mousepos,&(body->texture.source),margin) && body->selectedpath[0]=='\0') {
987 382
                 body->flag_drawbigtexture=1;
988 383
                 return(0); /* nothing else to do */
989 384
         }
990 385
         /* leftside backbutton */
991
-        if(is_imutil_insidexywh(mousepos,&(body->backxywh),0)) {
386
+        if(is_global_insidewhxy(mousedata->mousepos,&(body->backwhxy),0)) {
992 387
                 static char sep[]={SEP};
993 388
                 if((ptr=strrchr(dirdata->dirname,sep[0]))!=NULL) {
994 389
                         /* previous dir */
... ...
@@ -999,7 +394,7 @@ im_body_mouse(body_t *body, Vector2 mousepos, Vector2 wheel, int lmbpressed, int
999 394
                 }
1000 395
                 listing_get(&(dirdata->listing),body->rootdir,dirdata->dirname,1);
1001 396
                 body->dirdata[body->currentdirdata]->leftscrollpos=0;
1002
-                *click_avail=0;
397
+                mousedata->click_avail=0;
1003 398
                 return(0);
1004 399
         }
1005 400
         /* leftside directories */
... ...
@@ -1007,11 +402,11 @@ im_body_mouse(body_t *body, Vector2 mousepos, Vector2 wheel, int lmbpressed, int
1007 402
                 ld=dirdata->listing.elems+i;
1008 403
                 if(ld->name[0]!='d')
1009 404
                         continue;
1010
-                if(is_imutil_insidexywh(mousepos,&(ld->left.screenxywh),0)) {
405
+                if(is_global_insidewhxy(mousedata->mousepos,&(ld->left.screenwhxy),0)) {
1011 406
                         char *newname,*oldprefix;
1012 407
                         int l,l0,l1;
1013 408
                         static char sep[]={SEP};
1014
-                        oldprefix=(strcmp(dirdata->dirname,SEP)==0)?"":dirdata->dirname;
409
+                        oldprefix=(dirdata->dirname[0]==SEP && dirdata->dirname[1]=='\0')?"":dirdata->dirname;
1015 410
                         l0=strlen(oldprefix);
1016 411
                         l1=strlen(ld->name+1);
1017 412
                         l=l0+((l0>0)?1:0)+l1+1;
... ...
@@ -1027,48 +422,48 @@ im_body_mouse(body_t *body, Vector2 mousepos, Vector2 wheel, int lmbpressed, int
1027 422
                         dirdata->dirname=newname;
1028 423
                         listing_get(&(dirdata->listing),body->rootdir,dirdata->dirname,1);
1029 424
                         body->dirdata[body->currentdirdata]->leftscrollpos=0;
1030
-                        *click_avail=0;
425
+                        mousedata->click_avail=0;
1031 426
                         return(0);
1032 427
                 }
1033 428
         }
1034 429
         /* dirdata processing */
1035 430
         if(body->selectedpath[0]=='\0') {
1036 431
                 /* dirdata select */
1037
-                if(mousepos.x>body->leftsize && mousepos.y>body->xywh.y) {
432
+                if(mousedata->mousepos.x>body->leftsize && mousedata->mousepos.y>body->whxy.y) {
1038 433
                         int righty;
1039
-                        for(righty=body->xywh.y,i=0;i<body->sizedirdata;i++) {
434
+                        for(righty=body->whxy.y,i=0;i<body->sizedirdata;i++) {
1040 435
                                 if(body->dirdata[i]==NULL)
1041 436
                                         continue;
1042
-                                if(mousepos.y>=righty && mousepos.y<(righty+body->dirdata[i]->height) && i!=body->currentdirdata) {
437
+                                if(mousedata->mousepos.y>=righty && mousedata->mousepos.y<(righty+body->dirdata[i]->height) && i!=body->currentdirdata) {
1043 438
                                         body->currentdirdata=i;
1044
-                                        *click_avail=0;
439
+                                        mousedata->click_avail=0;
1045 440
                                         return(0);
1046 441
                                 }
1047 442
                                 righty+=body->dirdata[i]->height;
1048 443
                         }
1049 444
                 }
1050 445
                 /* detect click on "add dirdata" button */
1051
-                if(is_imutil_insidexywh(mousepos,&(body->dirdataadd),0)) {
446
+                if(is_global_insidewhxy(mousedata->mousepos,&(body->dirdataadd),0)) {
1052 447
                         im_body_add(body,body->dirdata[body->currentdirdata]->dirname);
1053
-                        *click_avail=0;
448
+                        mousedata->click_avail=0;
1054 449
                         return(0);
1055 450
                 }
1056 451
                 /* dirdata remove */
1057 452
 #warning TODO
1058 453
         }
1059 454
         /* unselect selectedpath */
1060
-        if(lmbpressed==0 && body->selectedpath[0]!='\0') {
1061
-                if(mousepos.x>body->leftsize && mousepos.y>body->xywh.y) {
455
+        if(mousedata->lmbpressed==0 && body->selectedpath[0]!='\0') {
456
+                if(mousedata->mousepos.x>body->leftsize && mousedata->mousepos.y>body->whxy.y) {
1062 457
                         int righty;
1063
-                        for(righty=body->xywh.y,i=0;i<body->sizedirdata;i++) {
458
+                        for(righty=body->whxy.y,i=0;i<body->sizedirdata;i++) {
1064 459
                                 if(body->dirdata[i]==NULL)
1065 460
                                         continue;
1066
-                                if(mousepos.y>=righty && mousepos.y<(righty+body->dirdata[i]->height) && i!=body->currentdirdata && strcmp(body->dirdata[i]->dirname,body->dirdata[body->currentdirdata]->dirname)!=0) {
461
+                                if(mousedata->mousepos.y>=righty && mousedata->mousepos.y<(righty+body->dirdata[i]->height) && i!=body->currentdirdata && strcmp(body->dirdata[i]->dirname,body->dirdata[body->currentdirdata]->dirname)!=0) {
1067 462
 #warning TODO
1068 463
 #if 1
1069 464
 fprintf(stderr,"WOULD MOVE \"%s/%s\" to \"%s\"\n",body->dirdata[body->currentdirdata]->dirname,body->selectedpath+1,body->dirdata[i]->dirname);
1070 465
 #endif
1071
-                                        *click_avail=0;
466
+                                        mousedata->click_avail=0;
1072 467
                                         break;
1073 468
                                 }
1074 469
                                 righty+=body->dirdata[i]->height;
... ...
@@ -1079,8 +474,13 @@ fprintf(stderr,"WOULD MOVE \"%s/%s\" to \"%s\"\n",body->dirdata[body->currentdir
1079 474
         return(0);
1080 475
 }
1081 476
 
477
+#ifdef MYFUNC
478
+#undef MYFUNC
479
+#define MYFUNC "im_body_draw"
480
+#endif
481
+
1082 482
 int
1083
-im_body_draw(body_t *body, Vector2 mousepos, int lmbdown, int rmbdown, int windowwidth, int windowheight, int *needs_nextredraw, int scrollspeed)
483
+im_body_draw(body_t *body, mousedata_t *mousedata, int windowwidth, int windowheight, int *needs_nextredraw)
1084 484
 {
1085 485
         int i,k,margin,righty;
1086 486
         int lastx,lasty;
... ...
@@ -1095,12 +495,13 @@ im_body_draw(body_t *body, Vector2 mousepos, int lmbdown, int rmbdown, int windo
1095 495
         thumb_t *thumb;
1096 496
         char statustooltip[1024];
1097 497
         thumb_t *selectedthumb;
498
+        IMDEBUG("Pre-sanitycheck");
1098 499
         if(body==NULL)
1099 500
                 return(-1);
1100 501
         font=body->ptrfont;
1101 502
         fontbig=body->ptrfontbig;
1102 503
         fonthuge=body->ptrfonthuge;
1103
-        FILLXYWH(body->backxywh,0,0,0,0);
504
+        FILLWHXY(body->backwhxy,0,0,0,0);
1104 505
         margin=font->height/4;
1105 506
         body->is_displayingtexture=0;
1106 507
         selectedthumb=NULL;
... ...
@@ -1108,14 +509,15 @@ im_body_draw(body_t *body, Vector2 mousepos, int lmbdown, int rmbdown, int windo
1108 509
         if(body->flag_drawbigtexture && body->texture.has_texture) {
1109 510
                 /* draw image in full screen */
1110 511
                 int maxw,maxh;
512
+                IMDEBUG("begin draw");
1111 513
                 maxw=windowwidth;
1112
-                maxh=windowheight-body->xywh.y;
514
+                maxh=windowheight-body->whxy.y;
1113 515
                 if(body->bigtexture.has_texture==0 || strcmp(body->bigtexture.currentpath,body->texture.currentpath)!=0)
1114 516
                         texture_load(&(body->bigtexture),body->texture.currentpath,maxw,maxh,body->bg);
1115 517
                 if(body->bigtexture.has_texture && strcmp(body->bigtexture.currentpath,body->texture.currentpath)==0) {
1116 518
                         int x0,y0;
1117 519
                         x0=0;
1118
-                        y0=body->xywh.y;
520
+                        y0=body->whxy.y;
1119 521
                         texture_draw(&(body->bigtexture),x0,y0,maxw,maxh);
1120 522
                         return(0); /* all done */
1121 523
                 } else {
... ...
@@ -1123,30 +525,47 @@ im_body_draw(body_t *body, Vector2 mousepos, int lmbdown, int rmbdown, int windo
1123 525
                 }
1124 526
         }
1125 527
         /* calculate positions */
528
+        IMDEBUG("calculate positions");
1126 529
         for(i=0;i<body->sizedirdata;i++) {
1127 530
                 if(body->dirdata[i]==NULL)
1128 531
                         continue;
1129
-                if(body->dirdata[i]->listing.has_rightxywh==0) {
532
+                if(body->dirdata[i]->listing.has_rightwhxy==0) {
1130 533
                         int sidelen;
1131 534
                         sidelen=body->dirdata[i]->height-(fontbig->height+fontbig->height/4+font->height+margin*4+fontbig->height/4);
1132
-                        listing_fillxywh(&(body->dirdata[i]->listing),body->ptrfont,body->xywh.w-(body->xywh.x+body->leftsize),sidelen,0);
1133
-                        body->dirdata[i]->listing.has_rightxywh=1;
535
+                        listing_fillwhxy(&(body->dirdata[i]->listing),body->ptrfont,body->whxy.w-(body->whxy.x+body->leftsize),sidelen,0,0);
536
+                        body->dirdata[i]->listing.has_rightwhxy=1;
1134 537
                 }
1135
-                if(i==body->currentdirdata && body->dirdata[i]->listing.has_leftxywh==0) {
1136
-                        listing_fillxywh(&(body->dirdata[i]->listing),body->ptrfont,body->leftsize,LEFTIMAGESIDELEN,1);
1137
-                        body->dirdata[i]->listing.has_leftxywh=1;
538
+                if(i==body->currentdirdata && body->dirdata[i]->listing.has_leftwhxy==0) {
539
+                        listing_fillwhxy(&(body->dirdata[i]->listing),body->ptrfont,body->leftsize,LEFTIMAGESIDELEN,1,0);
540
+                        body->dirdata[i]->listing.has_leftwhxy=1;
1138 541
                 }
1139 542
         }
1140 543
         /* draw left side background */
1141
-        DrawRectangle(body->xywh.x,body->xywh.y,body->leftsize, body->xywh.h, (Color){ 215, 215, 215, 255 } );
544
+        IMDEBUG("draw left bg");
545
+        {
546
+                whxy_t whxy;
547
+                FILLWHXY(whxy,body->leftsize, body->whxy.h,body->whxy.x,body->whxy.y);
548
+                rayui_scrollablerectadd(body->rayui,mousedata,&whxy,"body.leftside",body->dirdata[body->currentdirdata]->leftscrollpos,(int (*)(void *, Vector2))im_body_tryselect,body,SCROLLTHRESHOLD);
549
+        }
550
+        DrawRectangle(body->whxy.x,body->whxy.y,body->leftsize, body->whxy.h, (Color){ 215, 215, 215, 255 } );
551
+fprintf(stderr,"%ix%i+%i+%i\n",body->leftsize, body->whxy.h,body->whxy.x,body->whxy.y);
1142 552
         /* draw right side background */
1143
-        DrawRectangle(body->xywh.x+body->leftsize,body->xywh.y,body->xywh.w-body->leftsize, body->xywh.h, (Color){ 227, 227, 227, 255 } );
553
+#if 1
554
+fprintf(stderr,"body->whxy:%ix%i+%i+%i\n",UNROLLWHXY(body->whxy));
555
+fprintf(stderr,"body->leftsize:%i\n",body->leftsize);
556
+#endif
557
+        IMDEBUG("draw right bg");
558
+        DrawRectangle(body->whxy.x+body->leftsize,body->whxy.y,body->whxy.w-body->leftsize, body->whxy.h, (Color){ 227, 227, 227, 255 } );
559
+fprintf(stderr,"DrawRectangle(body->whxy.x(%i)+body->leftsize(%i),body->whxy.y(%i),body->whxy.w(%i)-body->leftsize(%i), body->whxy.h(%i), (Color){ 227, 227, 227, 255 } );\n"
560
+        ,body->whxy.x,body->leftsize,body->whxy.y,body->whxy.w,body->leftsize, body->whxy.h);
561
+
562
+fprintf(stderr,"%ix%i+%i+%i\n",body->whxy.w-body->leftsize, body->whxy.h,body->whxy.x+body->leftsize,body->whxy.y);
1144 563
         /* reset lazy load marks */
1145 564
         bg_resetmarks(body->bg);
1146 565
         /* first pass, draw leftside, second pass, draw all of rightside */
1147 566
         statustooltip[0]='\0';
1148 567
         for(is_leftside=1,flag_skiprightside=flag_skipall=0;is_leftside>=0 && flag_skiprightside==0 && flag_skipall==0;is_leftside--) {
1149
-                for(i=(is_leftside)?body->currentdirdata:0,righty=body->xywh.y;flag_skipall==0 && ((is_leftside && i==body->currentdirdata) || (!is_leftside && i<body->sizedirdata));i++) {
568
+                for(i=(is_leftside)?body->currentdirdata:0,righty=body->whxy.y;flag_skipall==0 && ((is_leftside && i==body->currentdirdata) || (!is_leftside && i<body->sizedirdata));i++) {
1150 569
                         int sidelen;
1151 570
                         if((dirdata=body->dirdata[i])==NULL)
1152 571
                                 continue;
... ...
@@ -1154,24 +573,24 @@ im_body_draw(body_t *body, Vector2 mousepos, int lmbdown, int rmbdown, int windo
1154 573
                                 continue; /* this element is not in leftside */
1155 574
                         sidelen=(is_leftside)?LEFTIMAGESIDELEN:dirdata->height-(fontbig->height+fontbig->height/4+font->height+margin*4+fontbig->height/4);
1156 575
                         /* draw left side back arrow if is_leftside and not in root dir */
1157
-                        if(is_leftside && !(dirdata->dirname[0]=='\0' || strcmp(dirdata->dirname,SEP)==0)) {
576
+                        if(is_leftside && !(dirdata->dirname[0]=='\0' || (dirdata->dirname[0]==SEP && dirdata->dirname[1]=='\0'))) {
1158 577
                                 m2=MeasureTextEx(fontbig->font,UTF8DOWNARROW,fontbig->height,0);
1159
-                                v2.x=(float) (body->xywh.x+fontbig->height/2);
1160
-                                v2.y=(float) (body->xywh.y+fontbig->height/4+(fontbig->height-v2.x)/2)-body->dirdata[body->currentdirdata]->leftscrollpos;
1161
-                                FILLXYWH(body->backxywh,v2.x-fontbig->height/4,v2.y-fontbig->height/8,m2.x+fontbig->height/4,m2.x+fontbig->height/4);
578
+                                v2.x=(float) (body->whxy.x+fontbig->height/2);
579
+                                v2.y=(float) (body->whxy.y+fontbig->height/4+(fontbig->height-v2.x)/2)-body->dirdata[body->currentdirdata]->leftscrollpos;
580
+                                FILLWHXY(body->backwhxy,m2.x+fontbig->height/4,m2.x+fontbig->height/4,v2.x-fontbig->height/4,v2.y-fontbig->height/8);
1162 581
 #if 0
1163 582
 DrawTexture(fontbig->font.texture, 0, 0, WHITE); /* font glyphs -- see https://github.com/raysan5/raylib/issues/2022 */
1164
-DrawRectangle(UNROLLXYWH(body->backxywh),((Color){ 0,255,0,255 })); /* hit zone */
583
+DrawRectangle(UNROLLXYWH(body->backwhxy),((Color){ 0,255,0,255 })); /* hit zone */
1165 584
 #endif
1166 585
                                 if((v2.y+fontbig->height)>=0)
1167 586
                                         DrawTextPro(fontbig->font,UTF8DOWNARROW,(Vector2){v2.x+m2.x,v2.y},(Vector2){0,0},90.0,fontbig->height,0,(Color){65,65,65,255});
1168 587
                         }
1169 588
                         if(is_leftside) {
1170 589
                                 /* ...dirname */
1171
-                                v2.y=(float) (body->xywh.y+fontbig->height/4-body->dirdata[body->currentdirdata]->leftscrollpos);
590
+                                v2.y=(float) (body->whxy.y+fontbig->height/4-body->dirdata[body->currentdirdata]->leftscrollpos);
1172 591
                                 if((v2.y+fontbig->height)>=0) {
1173 592
                                         m2=MeasureTextEx(fontbig->font,dirdata->dirname,fontbig->height,0);
1174
-                                        v2.x=(float) (body->xywh.x+fontbig->height/2)+(body->leftsize-(body->xywh.x+fontbig->height)-m2.x)/2;
593
+                                        v2.x=(float) (body->whxy.x+fontbig->height/2)+(body->leftsize-(body->whxy.x+fontbig->height)-m2.x)/2;
1175 594
                                         DrawTextEx(fontbig->font
1176 595
                                           ,dirdata->dirname
1177 596
                                           ,v2
... ...
@@ -1182,13 +601,13 @@ DrawRectangle(UNROLLXYWH(body->backxywh),((Color){ 0,255,0,255 })); /* hit zone
1182 601
                                 }
1183 602
                         } else { /* rightside */
1184 603
                                 /* ...bg */
1185
-                                DrawRectangle(body->xywh.x+body->leftsize,righty,body->xywh.w-body->leftsize, dirdata->height,(i==body->currentdirdata)?((Color){ 168, 168, 168, 255 }):((Color){ 227, 227, 227, 255 }));
604
+                                DrawRectangle(body->whxy.x+body->leftsize,righty,body->whxy.w-body->leftsize, dirdata->height,(i==body->currentdirdata)?((Color){ 168, 168, 168, 255 }):((Color){ 227, 227, 227, 255 }));
1186 605
                                 /* ...bottom separator */
1187
-                                DrawRectangle(body->xywh.x+body->leftsize,righty+dirdata->height-1,body->xywh.w-body->leftsize, 1, (Color){ 221, 221, 221, 255 } );
606
+                                DrawRectangle(body->whxy.x+body->leftsize,righty+dirdata->height-1,body->whxy.w-body->leftsize, 1, (Color){ 221, 221, 221, 255 } );
1188 607
                                 /* ...dirname */
1189 608
                                 DrawTextEx(fontbig->font
1190 609
                                   ,dirdata->dirname
1191
-                                  ,(Vector2) {body->xywh.x+body->leftsize+fontbig->height/2,righty+fontbig->height/4}
610
+                                  ,(Vector2) {body->whxy.x+body->leftsize+fontbig->height/2,righty+fontbig->height/4}
1192 611
                                   ,fontbig->height
1193 612
                                   ,0
1194 613
                                   ,(i==body->currentdirdata)?((Color){ 240, 240, 240, 255 }):((Color){ 65, 65, 65, 255 })
... ...
@@ -1196,7 +615,7 @@ DrawRectangle(UNROLLXYWH(body->backxywh),((Color){ 0,255,0,255 })); /* hit zone
1196 615
                         }
1197 616
                         /* directories */
1198 617
                         xoff=((is_leftside)?0:body->leftsize);
1199
-                        yoff=((is_leftside)?body->xywh.y:righty)+fontbig->height/4+fontbig->height+font->height/4-(is_leftside?body->dirdata[body->currentdirdata]->leftscrollpos:0);
618
+                        yoff=((is_leftside)?body->whxy.y:righty)+fontbig->height/4+fontbig->height+font->height/4-(is_leftside?body->dirdata[body->currentdirdata]->leftscrollpos:0);
1200 619
                         if(is_leftside && dirdata->dirname[0]=='\0')
1201 620
                                 yoff-=fontbig->height/4+fontbig->height;
1202 621
                         for(k=0,lastx=lasty=0;k<dirdata->listing.usedelems;k++) {
... ...
@@ -1204,51 +623,51 @@ DrawRectangle(UNROLLXYWH(body->backxywh),((Color){ 0,255,0,255 })); /* hit zone
1204 623
                                 thumb=(is_leftside)?&(elem->left):&(elem->right);
1205 624
                                 if(elem->name[0]!='d' || strcmp(elem->name,"d.")==0 || strcmp(elem->name,"d..")==0) {
1206 625
                                         if(elem->name[0]=='d')
1207
-                                                FILLXYWH(thumb->screenxywh,0,0,0,0);
626
+                                                FILLWHXY(thumb->screenwhxy,0,0,0,0);
1208 627
                                         continue;
1209 628
                                 }
1210
-                                if((thumb->xywh.y+yoff)>(body->xywh.y+body->xywh.h) || thumb->xywh.w==0 || thumb->xywh.h==0) {
629
+                                if((thumb->whxy.y+yoff)>(body->whxy.y+body->whxy.h) || thumb->whxy.w==0 || thumb->whxy.h==0) {
1211 630
 #warning TODO: if !is_leftside, draw "..." in huge font using lastx,lasty as reference
1212 631
                                         break;
1213 632
                                 }
1214
-                                if((thumb->xywh.y+yoff+thumb->xywh.h)<0) {
1215
-                                        FILLXYWH(thumb->screenxywh,0,0,0,0);
633
+                                if((thumb->whxy.y+yoff+thumb->whxy.h)<0) {
634
+                                        FILLWHXY(thumb->screenwhxy,0,0,0,0);
1216 635
                                         continue;
1217 636
                                 }
1218
-                                FILLXYWH(thumb->screenxywh,thumb->xywh.x+xoff,thumb->xywh.y+yoff,thumb->xywh.w,thumb->xywh.h);
1219
-                                DrawRectangleLines(UNROLLXYWH(thumb->screenxywh),((Color){ 65, 65, 65, 255 }));
1220
-                                DrawTextEx(font->font,elem->name+1,(Vector2){thumb->screenxywh.x+margin,thumb->screenxywh.y+margin},font->height,0,((Color){ 65, 65, 65, 255 }));
1221
-                                lastx=thumb->screenxywh.x+thumb->screenxywh.w,lasty=thumb->screenxywh.y+thumb->screenxywh.h;
637
+                                FILLWHXY(thumb->screenwhxy,thumb->whxy.w,thumb->whxy.h,thumb->whxy.x+xoff,thumb->whxy.y+yoff);
638
+                                DrawRectangleLines(thumb->screenwhxy.x,thumb->screenwhxy.y,thumb->screenwhxy.w,thumb->screenwhxy.h,((Color){ 65, 65, 65, 255 }));
639
+                                DrawTextEx(font->font,elem->name+1,(Vector2){thumb->screenwhxy.x+margin,thumb->screenwhxy.y+margin},font->height,0,((Color){ 65, 65, 65, 255 }));
640
+                                lastx=thumb->screenwhxy.x+thumb->screenwhxy.w,lasty=thumb->screenwhxy.y+thumb->screenwhxy.h;
1222 641
                         }
1223 642
                         for(;k<dirdata->listing.usedelems;k++) {
1224 643
                                 elem=dirdata->listing.elems+k;
1225 644
                                 if(elem->name[0]!='d')
1226 645
                                         continue;
1227 646
                                 thumb=(is_leftside)?&(elem->left):&(elem->right);
1228
-                                FILLXYWH(thumb->screenxywh,0,0,0,0);
647
+                                FILLWHXY(thumb->screenwhxy,0,0,0,0);
1229 648
                         }
1230 649
                         /* files */
1231 650
                         for(k=0,lastx=lasty=0;k<dirdata->listing.usedelems;k++) {
1232 651
                                 Texture2D *te;
1233
-                                xywh_t *xywh;
652
+                                whxy_t *whxy;
1234 653
                                 elem=dirdata->listing.elems+k;
1235 654
                                 thumb=(is_leftside)?&(elem->left):&(elem->right);
1236
-                                xywh=&(thumb->xywh);
655
+                                whxy=&(thumb->whxy);
1237 656
                                 te=&(thumb->texture);
1238 657
                                 int has_imagedrawn;
1239 658
                                 if(elem->name[0]!='f' && elem->name[0]!='l')
1240 659
                                         continue;
1241
-                                if((xywh->y+yoff)>(body->xywh.y+body->xywh.h) || xywh->w==0 || xywh->h==0) {
660
+                                if((whxy->y+yoff)>(body->whxy.y+body->whxy.h) || whxy->w==0 || whxy->h==0) {
1242 661
 #warning TODO: if !is_leftside, draw "..." in huge font using lastx,lasty as reference
1243 662
                                         break;
1244 663
                                 }
1245
-                                if(is_leftside && is_imutil_insidexywh(mousepos,&(thumb->screenxywh),margin)) {
664
+                                if(is_leftside && is_global_insidewhxy(mousedata->mousepos,&(thumb->screenwhxy),margin)) {
1246 665
                                         strncpy(statustooltip,elem->name+1,sizeof(statustooltip));
1247 666
                                         statustooltip[sizeof(statustooltip)-1]='\0';
1248 667
                                 }
1249 668
                                 /* show image */
1250 669
                                 has_imagedrawn=0;
1251
-                                if(is_imagefilename(elem->name+1) && !(thumb->screenxywh.y>(body->xywh.y+body->xywh.h) || (thumb->screenxywh.y+thumb->screenxywh.h)<body->xywh.y)) {
670
+                                if(is_imagefilename(elem->name+1) && !(thumb->screenwhxy.y>(body->whxy.y+body->whxy.h) || (thumb->screenwhxy.y+thumb->screenwhxy.h)<body->whxy.y)) {
1252 671
                                         if(thumb->has_texture==0 && thumb->has_failedload==0) {
1253 672
                                                 bgload_t *bgload;
1254 673
                                                 char fullpath[2048];
... ...
@@ -1291,16 +710,16 @@ fprintf(stderr,"elem:\"%s\" sidelen:%i old:%ix%i new:%ix%i\n",elem->name+1,sidel
1291 710
                                                 }
1292 711
                                         }
1293 712
                                         if(thumb->has_texture!=0) {
1294
-                                                FILLXYWH(thumb->screenxywh,xywh->x+xoff,xywh->y+yoff,xywh->w,xywh->h);
1295
-                                                DrawTexture(*te,thumb->screenxywh.x,thumb->screenxywh.y,WHITE);
713
+                                                FILLWHXY(thumb->screenwhxy,whxy->w,whxy->h,whxy->x+xoff,whxy->y+yoff);
714
+                                                DrawTexture(*te,thumb->screenwhxy.x,thumb->screenwhxy.y,WHITE);
1296 715
                                                 has_imagedrawn=1;
1297
-                                                lastx=xywh->x+xywh->w,lasty=xywh->y+xywh->h+yoff;
1298
-                                                if(is_leftside && rmbdown==0 && is_imutil_insidexywh(mousepos,&(thumb->screenxywh),margin) && scrollspeed==0) {
716
+                                                lastx=whxy->x+whxy->w,lasty=whxy->y+whxy->h+yoff;
717
+                                                if(is_leftside && mousedata->rmbdown==0 && is_global_insidewhxy(mousedata->mousepos,&(thumb->screenwhxy),margin) && mousedata->scrollspeed==0) {
1299 718
                                                         /* draw image in rightside */
1300 719
                                                         char fullpath[2048];
1301 720
                                                         int maxw,maxh;
1302 721
                                                         maxw=windowwidth-(body->leftsize-DEFAULTDIRDATATRIANGLEW);
1303
-                                                        maxh=windowheight-body->xywh.y;
722
+                                                        maxh=windowheight-body->whxy.y;
1304 723
                                                         snprintf(fullpath,sizeof(fullpath),"%s/%s/%s",body->rootdir,dirdata->dirname,elem->name+1);
1305 724
                                                         fullpath[sizeof(fullpath)-1]='\0';
1306 725
                                                         if((body->texture.has_texture==0 && !(body->texture.has_failedload && strcmp(body->texture.currentpath,fullpath)==0))
... ...
@@ -1311,10 +730,10 @@ fprintf(stderr,"elem:\"%s\" sidelen:%i old:%ix%i new:%ix%i\n",elem->name+1,sidel
1311 730
                                                         if(body->texture.has_texture && strcmp(body->texture.currentpath,fullpath)==0) {
1312 731
                                                                 int x0,y0;
1313 732
                                                                 x0=body->leftsize-DEFAULTDIRDATATRIANGLEW;
1314
-                                                                y0=body->xywh.y;
733
+                                                                y0=body->whxy.y;
1315 734
                                                                 texture_draw(&(body->texture),x0,y0,maxw,maxh);
1316 735
                                                                 body->is_displayingtexture=1;
1317
-                                                                memcpy(&(body->texture.source),&(thumb->screenxywh),sizeof(body->texture.source));
736
+                                                                memcpy(&(body->texture.source),&(thumb->screenwhxy),sizeof(body->texture.source));
1318 737
                                                                 flag_skiprightside=1;
1319 738
                                                         }
1320 739
                                                 }
... ...
@@ -1323,15 +742,15 @@ fprintf(stderr,"elem:\"%s\" sidelen:%i old:%ix%i new:%ix%i\n",elem->name+1,sidel
1323 742
                                 if(has_imagedrawn==0) {
1324 743
                                         char *ptr;
1325 744
                                         char shortname[1024];
1326
-                                        xywh_t *pos;
745
+                                        whxy_t *pos;
1327 746
                                         int l;
1328 747
                                         font_t *myfont=(is_leftside)?fonthuge:font;
1329
-                                        pos=is_leftside?&(elem->left.xywh):&(elem->right.xywh);
1330
-                                        FILLXYWH(thumb->screenxywh,xywh->x+xoff,xywh->y+yoff,xywh->w,xywh->h);
1331
-                                        DrawRectangle(UNROLLXYWH(thumb->screenxywh),((Color){0,0,0,64}));
748
+                                        pos=is_leftside?&(elem->left.whxy):&(elem->right.whxy);
749
+                                        FILLWHXY(thumb->screenwhxy,whxy->w,whxy->h,whxy->x+xoff,whxy->y+yoff);
750
+                                        DrawRectangle(thumb->screenwhxy.x,thumb->screenwhxy.y,thumb->screenwhxy.w,thumb->screenwhxy.h,((Color){0,0,0,64}));
1332 751
                                         if((ptr=strchr(elem->name+1,'.'))!=NULL) {
1333 752
                                                 m2=MeasureTextEx(myfont->font,ptr,myfont->height,0);
1334
-                                                DrawTextEx(myfont->font,ptr,(Vector2){xywh->x+xoff+(sidelen-m2.x)/2,xywh->y+yoff+(font->height)/2+(xywh->w-myfont->height)/2},myfont->height,0,(Color){ 0,0,0,96 });
753
+                                                DrawTextEx(myfont->font,ptr,(Vector2){whxy->x+xoff+(sidelen-m2.x)/2,whxy->y+yoff+(font->height)/2+(whxy->w-myfont->height)/2},myfont->height,0,(Color){ 0,0,0,96 });
1335 754
                                         }
1336 755
                                         ptr=(ptr==NULL)?elem->name+1:ptr;
1337 756
                                         l=(ptr-(elem->name+1));
... ...
@@ -1340,17 +759,17 @@ fprintf(stderr,"elem:\"%s\" sidelen:%i old:%ix%i new:%ix%i\n",elem->name+1,sidel
1340 759
                                         shortname[l]='\0';
1341 760
                                         DrawRectangle(pos->x+xoff,pos->y+yoff,pos->w,font->height+font->height/2,((Color){0,0,0,64}));
1342 761
                                         DrawTextEx(font->font,shortname,(Vector2){pos->x+xoff+font->height/4,pos->y+yoff+font->height/4},font->height,0,(Color){ 192,192,192,255 });
1343
-                                        lastx=xywh->x+xoff+xywh->w,lasty=xywh->y+yoff+xywh->h;
762
+                                        lastx=whxy->x+xoff+whxy->w,lasty=whxy->y+yoff+whxy->h;
1344 763
                                 }
1345 764
                                 /* show selected rectangle */
1346 765
                                 if(is_leftside && strcmp(body->selectedpath,elem->name)==0) {
1347 766
                                         Color c=((Color){0,0,255,64});
1348
-                                        DrawRectangle(UNROLLXYWH(thumb->screenxywh),c);
767
+                                        DrawRectangle(thumb->screenwhxy.x,thumb->screenwhxy.y,thumb->screenwhxy.w,thumb->screenwhxy.h,c);
1349 768
                                         c=((Color){0,0,255,255});
1350
-                                        DrawRectangle(thumb->screenxywh.x,thumb->screenxywh.y,thumb->screenxywh.w,2,c);
1351
-                                        DrawRectangle(thumb->screenxywh.x,thumb->screenxywh.y+2,2,thumb->screenxywh.h-4,c);
1352
-                                        DrawRectangle(thumb->screenxywh.x+thumb->screenxywh.w-2,thumb->screenxywh.y+2,2,thumb->screenxywh.h-4,c);
1353
-                                        DrawRectangle(thumb->screenxywh.x,thumb->screenxywh.y+thumb->screenxywh.h-2,thumb->screenxywh.w,2,c);
769
+                                        DrawRectangle(thumb->screenwhxy.x,thumb->screenwhxy.y,thumb->screenwhxy.w,2,c);
770
+                                        DrawRectangle(thumb->screenwhxy.x,thumb->screenwhxy.y+2,2,thumb->screenwhxy.h-4,c);
771
+                                        DrawRectangle(thumb->screenwhxy.x+thumb->screenwhxy.w-2,thumb->screenwhxy.y+2,2,thumb->screenwhxy.h-4,c);
772
+                                        DrawRectangle(thumb->screenwhxy.x,thumb->screenwhxy.y+thumb->screenwhxy.h-2,thumb->screenwhxy.w,2,c);
1354 773
                                         selectedthumb=thumb;
1355 774
                                 }
1356 775
                         }
... ...
@@ -1359,7 +778,7 @@ fprintf(stderr,"elem:\"%s\" sidelen:%i old:%ix%i new:%ix%i\n",elem->name+1,sidel
1359 778
                                 if(elem->name[0]!='f' && elem->name[0]!='l')
1360 779
                                         continue;
1361 780
                                 thumb=(is_leftside)?&(elem->left):&(elem->right);
1362
-                                FILLXYWH(thumb->screenxywh,0,0,0,0);
781
+                                FILLWHXY(thumb->screenwhxy,0,0,0,0);
1363 782
                         }
1364 783
                         /* ...finishing touchs */
1365 784
                         if(is_leftside) {
... ...
@@ -1367,29 +786,29 @@ fprintf(stderr,"elem:\"%s\" sidelen:%i old:%ix%i new:%ix%i\n",elem->name+1,sidel
1367 786
                         } else {
1368 787
                                 if(i==body->currentdirdata) {
1369 788
                                         /* draw right side "current" marker inside left side area */
1370
-                                        DrawTriangle((Vector2){((float)body->xywh.x)+body->leftsize,((float)righty)}, (Vector2){((float)body->xywh.x)+body->leftsize-DEFAULTDIRDATATRIANGLEW,((float)righty)+dirdata->height/2}, (Vector2){((float)body->xywh.x)+body->leftsize,((float)righty)+dirdata->height-1}, (Color){ 168, 168, 168, 255 } );
1371
-                                } else if(body->selectedpath[0]!='\0' && mousepos.x>body->leftsize && mousepos.y>=righty && mousepos.y<(righty+dirdata->height) && strcmp(body->dirdata[i]->dirname,body->dirdata[body->currentdirdata]->dirname)!=0) {
1372
-                                        xywh_t xywh;
789
+                                        DrawTriangle((Vector2){((float)body->whxy.x)+body->leftsize,((float)righty)}, (Vector2){((float)body->whxy.x)+body->leftsize-DEFAULTDIRDATATRIANGLEW,((float)righty)+dirdata->height/2}, (Vector2){((float)body->whxy.x)+body->leftsize,((float)righty)+dirdata->height-1}, (Color){ 168, 168, 168, 255 } );
790
+                                } else if(body->selectedpath[0]!='\0' && mousedata->mousepos.x>body->leftsize && mousedata->mousepos.y>=righty && mousedata->mousepos.y<(righty+dirdata->height) && strcmp(body->dirdata[i]->dirname,body->dirdata[body->currentdirdata]->dirname)!=0) {
791
+                                        whxy_t whxy;
1373 792
                                         Color c=((Color){0,0,255,64});
1374
-                                        FILLXYWH(xywh,body->leftsize,righty,body->xywh.w-body->leftsize,dirdata->height);
1375
-                                        DrawRectangle(UNROLLXYWH(xywh),c);
793
+                                        FILLWHXY(whxy,body->whxy.w-body->leftsize,dirdata->height,body->leftsize,righty);
794
+                                        DrawRectangle(whxy.x,whxy.y,whxy.w,whxy.h,c);
1376 795
                                         c=((Color){0,0,255,255});
1377
-                                        DrawRectangle(xywh.x,xywh.y,xywh.w,2,c);
1378
-                                        DrawRectangle(xywh.x,xywh.y+2,2,xywh.h-4,c);
1379
-                                        DrawRectangle(xywh.x+xywh.w-2,xywh.y+2,2,xywh.h-4,c);
1380
-                                        DrawRectangle(xywh.x,xywh.y+xywh.h-2,xywh.w,2,c);
796
+                                        DrawRectangle(whxy.x,whxy.y,whxy.w,2,c);
797
+                                        DrawRectangle(whxy.x,whxy.y+2,2,whxy.h-4,c);
798
+                                        DrawRectangle(whxy.x+whxy.w-2,whxy.y+2,2,whxy.h-4,c);
799
+                                        DrawRectangle(whxy.x,whxy.y+whxy.h-2,whxy.w,2,c);
1381 800
                                 }
1382 801
                                 /* advance to next element */
1383 802
                                 righty+=dirdata->height;
1384 803
                         }
1385 804
                 }
1386 805
         }
1387
-        if(flag_skiprightside==0 && (righty+DEFAULTDIRDATAHEIGHT)<=(body->xywh.y+body->xywh.h)) {
806
+        if(flag_skiprightside==0 && (righty+DEFAULTDIRDATAHEIGHT)<=(body->whxy.y+body->whxy.h)) {
1388 807
                 GlyphInfo gi;
1389 808
                 int xoff;
1390 809
                 int margin;
1391 810
                 margin=20;
1392
-                FILLXYWH(body->dirdataadd,(body->xywh.x+body->xywh.w-ADDREMOVEDIRDATAHEIGHT-margin),righty+margin,ADDREMOVEDIRDATAHEIGHT,ADDREMOVEDIRDATAHEIGHT);
811
+                FILLWHXY(body->dirdataadd,(body->whxy.x+body->whxy.w-ADDREMOVEDIRDATAHEIGHT-margin),righty+margin,ADDREMOVEDIRDATAHEIGHT,ADDREMOVEDIRDATAHEIGHT);
1393 812
                 gi=GetGlyphInfo(body->roundedbox,'O');
1394 813
                 xoff=0;
1395 814
                 DrawTexturePro(body->roundedbox.texture
... ...
@@ -1413,10 +832,10 @@ fprintf(stderr,"elem:\"%s\" sidelen:%i old:%ix%i new:%ix%i\n",elem->name+1,sidel
1413 832
         } else {
1414 833
                 memset(&(body->dirdataadd),0,sizeof(body->dirdataadd));
1415 834
         }
1416
-        /* if moving elem, show line from orig to mousepos */
835
+        /* if moving elem, show line from orig to mousedata->mousepos */
1417 836
         if(body->selectedpath[0]!='\0' && selectedthumb!=NULL) {
1418 837
                 Color c=((Color){0,0,255,255});
1419
-                DrawLineEx((Vector2){(float)(selectedthumb->screenxywh.x+selectedthumb->screenxywh.w/2),(float)(selectedthumb->screenxywh.y+selectedthumb->screenxywh.h/2)},mousepos,2.0,c);
838
+                DrawLineEx((Vector2){(float)(selectedthumb->screenwhxy.x+selectedthumb->screenwhxy.w/2),(float)(selectedthumb->screenwhxy.y+selectedthumb->screenwhxy.h/2)},mousedata->mousepos,2.0,c);
1420 839
         }
1421 840
         /* show tooltip */
1422 841
         if(statustooltip[0]!='\0') {
... ...
@@ -1425,242 +844,21 @@ fprintf(stderr,"elem:\"%s\" sidelen:%i old:%ix%i new:%ix%i\n",elem->name+1,sidel
1425 844
                 DrawTextEx(font->font,statustooltip,(Vector2){margin,windowheight-1-margin-font->height},font->height,0,(Color){ 255,255,255,128 });
1426 845
         }
1427 846
         /* free not used bg load items (only if idle, as it takes time) */
1428
-        if(scrollspeed==0 && *needs_nextredraw==0)
847
+        if(mousedata->scrollspeed==0 && *needs_nextredraw==0)
1429 848
                 bg_freeunmarked(body->bg);
1430 849
         return(0);
1431 850
 }
1432 851
 
1433
-int
1434
-texture_load(texture_t *texture, char *fullpath, int maxw, int maxh, bg_t *bg)
1435
-{ 
1436
-        Image im;
1437
-        int neww,newh;
1438
-        bgload_t *bgload;
1439
-        if(texture==NULL || fullpath==NULL)
1440
-                return(-1); /* sanity check failed */
1441
-        if(texture->has_texture) {
1442
-                UnloadTexture(texture->texture);
1443
-                texture->currentpath[0]='\0';
1444
-                texture->has_texture=0;
1445
-                texture->has_failedload=0;
1446
-        }
1447
-        texture->currentpath[0]='\0';
1448
-        if(bg!=NULL && (bgload=bg_get(bg,texture->currentpath))!=NULL && bgload->has_data!=0) {
1449
-                im=ImageCopy(bgload->image);
1450
-        } else {
1451
-                im=imutil_loadimage(fullpath);
1452
-        }
1453
-        if(IsImageValid(im)) {
1454
-                imutil_aspectmaximize(im.width,im.height,maxw,maxh,&neww,&newh);
1455
-                ImageResize(&im,neww,newh);
1456
-                texture->texture=LoadTextureFromImage(im);
1457
-                UnloadImage(im);
1458
-                strncpy(texture->currentpath,fullpath,sizeof(texture->currentpath));
1459
-                texture->currentpath[sizeof(texture->currentpath)-1]='\0';
1460
-                texture->has_texture=1;
1461
-                texture->has_failedload=0;
1462
-                texture->texturew=neww;
1463
-                texture->textureh=newh;
1464
-        } else {
1465
-                strncpy(texture->currentpath,fullpath,sizeof(texture->currentpath));
1466
-                texture->currentpath[sizeof(texture->currentpath)-1]='\0';
1467
-                texture->has_texture=0;
1468
-                texture->has_failedload=1;
1469
-        }
1470
-        return(0);
1471
-}
1472
-
1473
-int
1474
-texture_draw(texture_t *texture, int x0, int y0, int maxw, int maxh)
1475
-{
1476
-        if(texture==NULL || texture->has_texture==0)
1477
-                return(-1); /* sanity check failed */
1478
-        DrawRectangle(x0,y0,maxw,maxh,(Color){ 215, 215, 215, 255 } );
1479
-        DrawTexture(texture->texture,x0+(maxw-texture->texturew)/2,y0+(maxh-texture->textureh)/2,WHITE);
1480
-        return(0);
1481
-}
1482
-
1483
-int
1484
-texture_freedata(texture_t *texture)
1485
-{
1486
-        if(texture==NULL)
1487
-                return(-1); /* sanity check failed */
1488
-        if(texture->has_texture) {
1489
-                UnloadTexture(texture->texture);
1490
-                texture->currentpath[0]='\0';
1491
-                texture->has_texture=0;
1492
-                texture->has_failedload=0;
1493
-        }
1494
-        return(0);
1495
-}
1496
-
1497
-int
1498
-imutil_menu_count(char *menus)
1499
-{
1500
-        int n;
1501
-        char *ptr,*next;
1502
-        if(menus==NULL)
1503
-                return(0); /* sanity check error */
1504
-        for(ptr=menus,n=0;(next=strchr(ptr,'\n'))!=NULL;ptr=next+1) {
1505
-                if(next[1]=='\n') {
1506
-                        next++;
1507
-                        n++;
1508
-                }
1509
-        }
1510
-        return(n);
1511
-}
1512
-
1513
-char *
1514
-imutil_menu_get(char *menus, int targetn, int *len)
1515
-{
1516
-        int n;
1517
-        char *ptr,*next,*end;
1518
-        int is_title;
1519
-        if(len!=NULL)
1520
-                *len=0;
1521
-        if(menus==NULL || targetn<0)
1522
-                return(NULL); /* sanity check error */
1523
-        end=menus+strlen(menus);
1524
-        for(ptr=menus,is_title=1,n=0;(next=strchr(ptr,'\n'))!=NULL;ptr=next+1) {
1525
-                if(targetn==n && is_title==1) {
1526
-                        if(len!=NULL)
1527
-                                *len=next-ptr;
1528
-                        return(ptr); /* found, return start of menu string */
1529
-                }
1530
-                is_title=0;
1531
-                if(next[1]=='\n') {
1532
-                        n++;
1533
-                        next++;
1534
-                        is_title=1;
1535
-                }
1536
-        }
1537
-        return(end); /* not found, return end of menus */
1538
-}
1539
-
1540
-int
1541
-imutil_submenu_count(char *menus)
1542
-{
1543
-        int subn;
1544
-        char *ptr,*next;
1545
-        if(menus==NULL)
1546
-                return(0); /* sanity check error */
1547
-        next=strchr(menus,'\n');
1548
-        if(next==NULL)
1549
-                return(0); /* no title */
1550
-        for(subn=0,ptr=next+1;(next=strchr(ptr,'\n'))!=NULL;ptr=next+1) {
1551
-                subn++;
1552
-                if(next[1]=='\n')
1553
-                        break;
1554
-        }
1555
-        return(subn);
1556
-}
1557
-
1558
-char *
1559
-imutil_submenu_get(char *menus, int targetsubn, int *len)
1560
-{
1561
-        char *ptr,*next,*end;
1562
-        int subn;
1563
-        if(len!=NULL)
1564
-                *len=0;
1565
-        if(menus==NULL || targetsubn<0)
1566
-                return(NULL); /* sanity check error */
1567
-        end=menus+strlen(menus);
1568
-        next=strchr(menus,'\n');
1569
-        if(next==NULL)
1570
-                return(end); /* no title */
1571
-        for(ptr=next+1,subn=0;(next=strchr(ptr,'\n'))!=NULL;ptr=next+1,subn++) {
1572
-                if(targetsubn==subn) {
1573
-                        if(len!=NULL)
1574
-                                *len=next-ptr;
1575
-                        return(ptr);
1576
-                }
1577
-                if(next[1]=='\n')
1578
-                        break; /* "\n\n" marks the end of submenus */
1579
-        }
1580
-        return(end);
1581
-}
1582
-
1583
-char *
1584
-imutil_strduplen(char *str, int len)
1585
-{
1586
-        char *res;
1587
-        if(len<0 || (str==NULL && len!=0))
1588
-                return(NULL);
1589
-        if((res=malloc(len+1))==NULL)
1590
-                return(NULL);
1591
-        memcpy(res,str,len);
1592
-        res[len]='\0';
1593
-        return(res);
1594
-}
1595
-
1596
-int
1597
-is_imutil_insidexywh(Vector2 pos, xywh_t *xywh, int margin)
1598
-{
1599
-        if(xywh==NULL)
1600
-                return(0); /* sanity check error */
1601
-        if(pos.x>=(float)(xywh->x-margin)
1602
-          && pos.x<=(float)(xywh->x+xywh->w+margin)
1603
-          && pos.y>=(float)(xywh->y-margin)
1604
-          && pos.y<=(float)(xywh->y+xywh->h+margin)
1605
-        ) {
1606
-                return(1);
1607
-        }
1608
-        return(0);
1609
-}
1610
-
1611
-int
1612
-imutil_aspectmaximize(int w, int h, int maxw, int maxh, int *neww, int *newh)
1613
-{
1614
-        if(neww==NULL || newh==NULL || w==0 || h==0 || maxw==0 || maxh==0)
1615
-                return(-1);
1616
-        if((w/h)>(maxw/maxh) || (maxw==maxh && w>h)) {
1617
-                *neww=maxw;
1618
-                *newh=h*maxw/w;
1619
-        } else { /* (w/h)<=(maxw/maxh) */
1620
-                *newh=maxh;
1621
-                *neww=w*maxh/h;
1622
-        }
1623
-        return(0);
1624
-}
1625
-
1626
-
1627
-int
1628
-menudata_pos2option(menudata_t *menudata, Vector2 pos)
1629
-{
1630
-        int n,h;
1631
-        if(menudata==NULL
1632
-          || (menudata->flag_open==0 && menudata->flag_stickyopen==0)
1633
-          || is_imutil_insidexywh(pos, &(menudata->optionsxywh),0)==0
1634
-        ) {
1635
-                return(-1);
1636
-        }
1637
-        h=(menudata->sizeoptions==0)?0:menudata->optionsxywh.h/menudata->sizeoptions;
1638
-        n=(((int)pos.y)-menudata->optionsxywh.y)/h;
1639
-        return(n);
1640
-}
1641
-
1642
-int *
1643
-getcodepoints(int *sizecodepoints)
1644
-{
1645
-        static int codepoints[]={
1646
-/* Basic Latin */
1647
-32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
1648
-/* Latin-1 Supplement */
1649
-160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,
1650
-/* down arrow (U+2186 -- this font doesn't have arrows, this is old roman numeral 50 */
1651
-(0x21<<8)|0x86,
1652
-};
1653
-        if(sizecodepoints!=NULL)
1654
-                *sizecodepoints=(int) (sizeof(codepoints)/sizeof(codepoints[0]));
1655
-        return(codepoints);
1656
-}
1657
-
1658 852
 static int
1659 853
 strptrcmp(void *a,void *b)
1660 854
 {
1661 855
         return(strcmp(((listingdata_t *)a)->name,((listingdata_t *)b)->name));
1662 856
 }
1663 857
 
858
+#ifdef MYFUNC
859
+#undef MYFUNC
860
+#define MYFUNC "listing_get"
861
+#endif
1664 862
 int
1665 863
 listing_get(listing_t *listing, char *pathprefix, char *parampath, int flag_sort)
1666 864
 {
... ...
@@ -1689,11 +887,11 @@ listing_get(listing_t *listing, char *pathprefix, char *parampath, int flag_sort
1689 887
         /* reset struct */
1690 888
         listing->usedelems=listing->usedbuf=0;
1691 889
         memset(listing->elems,0,sizeof(listingdata_t)*listing->sizeelems);
1692
-        listing->has_leftxywh=listing->has_rightxywh=0;
890
+        listing->has_leftwhxy=listing->has_rightwhxy=0;
1693 891
         /* fill listing */
1694 892
         if(pathprefix==NULL && parampath==NULL)
1695 893
                 return(-1); /* nothing to fill */
1696
-        snprintf(path,sizeof(path),"%s%s%s",(pathprefix!=NULL)?pathprefix:"",SEP,(parampath!=NULL)?parampath:"");
894
+        snprintf(path,sizeof(path),"%s%c%s",(pathprefix!=NULL)?pathprefix:"",SEP,(parampath!=NULL)?parampath:"");
1697 895
         path[sizeof(path)-1]='\0';
1698 896
         if((d=opendir(path))==NULL)
1699 897
                 return(-1); /* dir not found */
... ...
@@ -1714,7 +912,7 @@ listing_get(listing_t *listing, char *pathprefix, char *parampath, int flag_sort
1714 912
                         char stpath[2048];
1715 913
                         struct stat st;
1716 914
                         mode_t m;
1717
-                        snprintf(stpath,sizeof(stpath),"%s%s%s",path,SEP,de->d_name);
915
+                        snprintf(stpath,sizeof(stpath),"%s%c%s",path,SEP,de->d_name);
1718 916
                         stpath[sizeof(stpath)-1]='\0';
1719 917
                         if(stat(stpath,&st)==0 && (m=(st.st_mode&S_IFMT))!=0) {
1720 918
                                 dtype=(m==S_IFBLK)?'b'
... ...
@@ -1767,6 +965,7 @@ listing_get(listing_t *listing, char *pathprefix, char *parampath, int flag_sort
1767 965
                 listing->elems[listing->usedelems++].name=listing->buf+listing->usedbuf;
1768 966
                 listing->buf[listing->usedbuf++]=dtype;
1769 967
                 memcpy(listing->buf+listing->usedbuf,de->d_name,l+1);
968
+IMDEBUG(listing->buf+listing->usedbuf);
1770 969
                 listing->usedbuf+=l+1;
1771 970
         }
1772 971
         closedir(d),d=NULL;
... ...
@@ -1804,7 +1003,7 @@ listing_freedata(listing_t *listing)
1804 1003
 }
1805 1004
 
1806 1005
 int
1807
-listing_fillxywh(listing_t *listing, font_t *font, int w, int sidelen, int is_leftside)
1006
+listing_fillwhxy(listing_t *listing, font_t *font, int w, int sidelen, int is_leftside, int rightsidemargin)
1808 1007
 {
1809 1008
         int x0,y0,x1;
1810 1009
         int k,x,y;
... ...
@@ -1816,14 +1015,14 @@ listing_fillxywh(listing_t *listing, font_t *font, int w, int sidelen, int is_le
1816 1015
                 return(-1); /* sanity check failed */
1817 1016
         margin=font->height/4;
1818 1017
         if(is_leftside)
1819
-                memset(&(listing->lastleftxywh),0,sizeof(listing->lastleftxywh));
1018
+                memset(&(listing->lastleftwhxy),0,sizeof(listing->lastleftwhxy));
1820 1019
         /* directories */
1821 1020
         if(is_leftside) {
1822 1021
                 x0=font->height/2;
1823 1022
                 x1=w-DEFAULTDIRDATATRIANGLEW-font->height/2;
1824 1023
                 y0=0;
1825 1024
         } else {
1826
-                x0=FONTBIGSIZE/2;
1025
+                x0=rightsidemargin;
1827 1026
                 x1=w-font->height/2;
1828 1027
                 y0=0;
1829 1028
         }
... ...
@@ -1836,12 +1035,12 @@ listing_fillxywh(listing_t *listing, font_t *font, int w, int sidelen, int is_le
1836 1035
                 if((x+margin*2+m2.x)>x1 && !(is_leftside==0 && y>y0))
1837 1036
                         x=x0,y+=font->height+margin*2+font->height/4;
1838 1037
                 if(is_leftside==0 && y>y0) {
1839
-                        FILLXYWH(thumb->xywh,0,0,0,0);
1038
+                        FILLWHXY(thumb->whxy,0,0,0,0);
1840 1039
                         continue;
1841 1040
                 }
1842
-                FILLXYWH(thumb->xywh,x,y,margin*2+m2.x,margin*2+font->height);
1843
-                if(is_leftside && (thumb->xywh.y+thumb->xywh.h)>(listing->lastleftxywh.y+listing->lastleftxywh.h))
1844
-                        memcpy(&(listing->lastleftxywh),&(thumb->xywh),sizeof(xywh_t));
1041
+                FILLWHXY(thumb->whxy,margin*2+m2.x,margin*2+font->height,x,y);
1042
+                if(is_leftside && (thumb->whxy.y+thumb->whxy.h)>(listing->lastleftwhxy.y+listing->lastleftwhxy.h))
1043
+                        memcpy(&(listing->lastleftwhxy),&(thumb->whxy),sizeof(whxy_t));
1845 1044
                 x+=margin*2+m2.x+font->height/4;
1846 1045
         }
1847 1046
         y+=((x==x0)?0:font->height+margin*2+font->height/4);
... ...
@@ -1856,18 +1055,18 @@ listing_fillxywh(listing_t *listing, font_t *font, int w, int sidelen, int is_le
1856 1055
                 if(elem->name[0]!='f' && elem->name[0]!='l')
1857 1056
                         continue;
1858 1057
                 if(!is_leftside && y>y0) {
1859
-                        FILLXYWH(thumb->xywh,0,0,0,0);
1058
+                        FILLWHXY(thumb->whxy,0,0,0,0);
1860 1059
                         continue;
1861 1060
                 }
1862 1061
                 if((x+margin*2+sidelen)>x1 && !(is_leftside==0 && y>y0))
1863 1062
                         x=x0,y+=sidelen+margin*2;
1864 1063
                 if(is_leftside==0 && y>y0) {
1865
-                        FILLXYWH(thumb->xywh,0,0,0,0);
1064
+                        FILLWHXY(thumb->whxy,0,0,0,0);
1866 1065
                         continue;
1867 1066
                 }
1868
-                FILLXYWH(thumb->xywh,x,y,sidelen,sidelen);
1869
-                if(is_leftside && (thumb->xywh.y+thumb->xywh.h)>(listing->lastleftxywh.y+listing->lastleftxywh.h))
1870
-                        memcpy(&(listing->lastleftxywh),&(thumb->xywh),sizeof(xywh_t));
1067
+                FILLWHXY(thumb->whxy,sidelen,sidelen,x,y);
1068
+                if(is_leftside && (thumb->whxy.y+thumb->whxy.h)>(listing->lastleftwhxy.y+listing->lastleftwhxy.h))
1069
+                        memcpy(&(listing->lastleftwhxy),&(thumb->whxy),sizeof(whxy_t));
1871 1070
                 x+=margin*2+sidelen;
1872 1071
         }
1873 1072
         return(0);
... ...
@@ -1899,313 +1098,82 @@ is_imagefilename(char *filename)
1899 1098
         return(0); /* not in the knownext list */
1900 1099
 }
1901 1100
 
1902
-#ifdef ANDROID
1903
-Image
1904
-imutil_loadimage(const char *filename)
1905
-{
1906
-        unsigned char *filedata=NULL;
1907
-        FILE *f=NULL;
1908
-        struct stat st;
1909
-        Image img;
1910
-        char *ext;
1911
-        if((f=fopen(filename,"r"))==NULL
1912
-          || fstat(fileno(f),&st)!=0
1913
-          || st.st_size<=0
1914
-          || (filedata=(unsigned char *)malloc(st.st_size))==NULL
1915
-          || fread(filedata,1,st.st_size,f)!=st.st_size
1916
-        ) {
1917
-                if(f!=NULL)
1918
-                        fclose(f),f=NULL;
1919
-                if(filedata!=NULL)
1920
-                        free(filedata),filedata=NULL;
1921
-                return((Image){0});
1922
-        }
1923
-        fclose(f);
1924
-        ext=strchr(filename,'.');
1925
-        ext=(ext==NULL)?filename+strlen(filename):ext;
1926
-        img=LoadImageFromMemory(ext,filedata,st.st_size);
1927
-        free(filedata),filedata=NULL;
1928
-        return(img);
1929
-}
1930
-#else
1931
-Image
1932
-imutil_loadimage(const char *filename)
1933
-{
1934
-        return(LoadImage(filename));
1935
-}
1936
-#endif
1937
-
1938
-static void
1939
-intimutil_fpsdata(struct timeval **deadline)
1940
-{
1941
-        static struct timeval mydeadline;
1942
-        *deadline=&(mydeadline);
1943
-        return;
1944
-}
1945
-
1946
-void
1947
-imutil_fpsreset(void)
1948
-{
1949
-        struct timeval *deadline;
1950
-        long deadlineincr;
1951
-        intimutil_fpsdata(&deadline);
1952
-        gettimeofday(deadline,NULL);
1953
-        deadlineincr=1000000L/TARGETFPS;
1954
-        deadline->tv_usec+=deadlineincr;
1955
-        deadline->tv_sec+=(deadline->tv_usec)/1000000L;
1956
-        deadline->tv_usec%=1000000L;
1957
-}
1958
-
1959 1101
 int
1960
-imutil_fpsleft(void)
1961
-{
1962
-        struct timeval *deadline,now;
1963
-        intimutil_fpsdata(&deadline);
1964
-        gettimeofday(&now,NULL);
1965
-        if(deadline->tv_sec<now.tv_sec || (deadline->tv_sec==now.tv_sec && deadline->tv_usec<now.tv_usec))
1966
-                return(0);
1967
-        return(1);
1968
-}
1969
-
1970
-long long
1971
-imutil_milliseconds(void)
1972
-{
1973
-        long long res;
1974
-        struct timeval now;
1975
-        gettimeofday(&now,NULL);
1976
-        res=((long long) (now.tv_sec))*1000000L+((long long) (now.tv_usec));
1977
-        return(res);
1978
-}
1979
-
1980
-bg_t *
1981
-bg_init(int sizebgload)
1102
+texture_load(texture_t *texture, char *fullpath, int maxw, int maxh, bg_t *bg)
1982 1103
 {
1983
-        bg_t *bg;
1984
-        char *errstr;
1985
-        bg=NULL;
1986
-        if((errstr="Insuf. mem. for bg")==NULL
1987
-          || (bg=calloc(1,sizeof(bg_t)))==NULL
1988
-          || (errstr="Error init pipes (please check program is not blocked in firewall)")==NULL
1989
-          || (bg->pipe[0]=bg->pipe[1]=-1)!=-1
1990
-          || mypipe(bg->pipe)!=0
1991
-          || (errstr="Insuf mem bgload")==NULL
1992
-          || (bg->bgload=calloc(sizebgload,sizeof(bgload_t)))==NULL
1993
-          || (bg->sizebgload=sizebgload)!=sizebgload
1994
-          || (errstr="pthread attr init error")==NULL
1995
-          || pthread_attr_init(&(bg->tattr))!=0
1996
-          || (errstr="pthread create error")==NULL
1997
-          || pthread_create(&(bg->thread),&(bg->tattr),bg_thread,(void *)bg)!=0
1998
-          || (bg->flag_threadstarted=1)!=1
1999
-        ) {
2000
-                messagebox(errstr);
2001
-                bg_free(bg);
2002
-                return(NULL);
1104
+        Image im;
1105
+        int neww,newh;
1106
+        bgload_t *bgload;
1107
+        if(texture==NULL || fullpath==NULL)
1108
+                return(-1); /* sanity check failed */
1109
+        if(texture->has_texture) {
1110
+                UnloadTexture(texture->texture);
1111
+                texture->currentpath[0]='\0';
1112
+                texture->has_texture=0;
1113
+                texture->has_failedload=0;
2003 1114
         }
2004
-        return(bg);
2005
-}
2006
-
2007
-
2008
-void
2009
-bg_free(bg_t *bg)
2010
-{
2011
-        int i;
2012
-        if(bg==NULL)
2013
-                return; /* nothing to do */
2014
-        if(bg->flag_threadstarted) {
2015
-                char dummy=1;
2016
-#if 1
2017
-fprintf(stderr,"bg_free: notifying thread to exit\n");
2018
-#endif
2019
-                mypipewrite(bg->pipe[WR],&dummy,1);
2020
-#if 1
2021
-fprintf(stderr,"bg_free: joining thread\n");
2022
-#endif
2023
-                pthread_join(bg->thread,NULL);
2024
-#if 1
2025
-fprintf(stderr,"bg_free: thread joined OK\n");
2026
-#endif
2027
-                bg->flag_threadstarted=0;
1115
+        texture->currentpath[0]='\0';
1116
+        if(bg!=NULL && (bgload=bg_get(bg,texture->currentpath))!=NULL && bgload->has_data!=0) {
1117
+                im=ImageCopy(bgload->image);
1118
+        } else {
1119
+                im=global_loadimage(fullpath);
2028 1120
         }
2029
-        if(bg->pipe[0]!=-1)
2030
-                close(bg->pipe[0]),bg->pipe[0]=-1;
2031
-        if(bg->pipe[1]!=-1)
2032
-                close(bg->pipe[1]),bg->pipe[1]=-1;
2033
-        if(bg->bgload!=NULL) {
2034
-                bgload_t *bgload;
2035
-                for(i=0,bgload=bg->bgload;i<bg->sizebgload;i++,bgload++) {
2036
-                        if(bgload->has_data) {
2037
-                                UnloadImage(bgload->image);
2038
-                                bgload->has_data=0;
2039
-                        }
2040
-                }
2041
-                free(bg->bgload),bg->bgload=NULL,bg->sizebgload=0;
1121
+        if(IsImageValid(im)) {
1122
+                imutil_aspectmaximize(im.width,im.height,maxw,maxh,&neww,&newh);
1123
+                ImageResize(&im,neww,newh);
1124
+                texture->texture=LoadTextureFromImage(im);
1125
+                UnloadImage(im);
1126
+                strncpy(texture->currentpath,fullpath,sizeof(texture->currentpath));
1127
+                texture->currentpath[sizeof(texture->currentpath)-1]='\0';
1128
+                texture->has_texture=1;
1129
+                texture->has_failedload=0;
1130
+                texture->texturew=neww;
1131
+                texture->textureh=newh;
1132
+        } else {
1133
+                strncpy(texture->currentpath,fullpath,sizeof(texture->currentpath));
1134
+                texture->currentpath[sizeof(texture->currentpath)-1]='\0';
1135
+                texture->has_texture=0;
1136
+                texture->has_failedload=1;
2042 1137
         }
2043
-        return;
1138
+        return(0);
2044 1139
 }
2045 1140
 
2046 1141
 int
2047
-bg_resetmarks(bg_t *bg)
1142
+texture_draw(texture_t *texture, int x0, int y0, int maxw, int maxh)
2048 1143
 {
2049
-        int i;
2050
-        bgload_t *bgload;
2051
-        if(bg==NULL)
2052
-                return(-1);
2053
-        for(i=0,bgload=bg->bgload;i<bg->sizebgload;i++,bgload++)
2054
-                bgload->has_mark=0;
1144
+        if(texture==NULL || texture->has_texture==0)
1145
+                return(-1); /* sanity check failed */
1146
+        DrawRectangle(x0,y0,maxw,maxh,(Color){ 215, 215, 215, 255 } );
1147
+        DrawTexture(texture->texture,x0+(maxw-texture->texturew)/2,y0+(maxh-texture->textureh)/2,WHITE);
2055 1148
         return(0);
2056 1149
 }
2057 1150
 
2058
-bgload_t *
2059
-bg_get(bg_t *bg, char *path)
2060
-{
2061
-        int i;
2062
-        bgload_t *bgload;
2063
-        if(bg==NULL)
2064
-                return(NULL);
2065
-        for(i=0,bgload=bg->bgload;i<bg->sizebgload;i++,bgload++) {
2066
-                if(bgload->thread_finished && bgload->has_data && strcmp(path,bgload->path)==0) {
2067
-                        bgload->has_mark=1;
2068
-#if 1
2069
-fprintf(stderr,"bg_get: \"%s\"\n",bgload->path);
2070
-#endif
2071
-                        return(bgload);
2072
-                }
2073
-        }
2074
-        return(NULL);
2075
-}
2076
-
2077 1151
 int
2078
-bg_add(bg_t *bg, char *path)
1152
+texture_freedata(texture_t *texture)
2079 1153
 {
2080
-        int i;
2081
-        bgload_t *bgload;
2082
-        char dummy;
2083
-        if(bg==NULL)
2084
-                return(-1);
2085
-        for(i=0,bgload=bg->bgload;i<bg->sizebgload;i++,bgload++) {
2086
-                if(bgload->lended_to_thread && strcmp(path,bgload->path)==0) {
2087
-                        bgload->is_todo=1;
2088
-                        bgload->has_mark=1;
2089
-                        dummy=0;
2090
-                        mypipewrite(bg->pipe[WR],&dummy,1);
2091
-                        return(0); /* already on list */
2092
-                }
2093
-        }
2094
-        for(i=0,bgload=bg->bgload;i<bg->sizebgload;i++,bgload++) {
2095
-                if(bgload->lended_to_thread==0) {
2096
-                        memset(bgload,0,sizeof(bgload_t));
2097
-                        strncpy(bgload->path,path,sizeof(bgload->path));
2098
-                        bgload->path[sizeof(bgload->path)-1]='\0';
2099
-                        bgload->is_todo=1;
2100
-                        bgload->has_mark=1;
2101
-                        dummy=0;
2102
-                        bgload->lended_to_thread=1;
2103
-                        mypipewrite(bg->pipe[WR],&dummy,1);
2104
-                        return(0); /* added to list */
2105
-                }
1154
+        if(texture==NULL)
1155
+                return(-1); /* sanity check failed */
1156
+        if(texture->has_texture) {
1157
+                UnloadTexture(texture->texture);
1158
+                texture->currentpath[0]='\0';
1159
+                texture->has_texture=0;
1160
+                texture->has_failedload=0;
2106 1161
         }
2107
-        return(-1); /* couldn't add */
1162
+        return(0);
2108 1163
 }
2109 1164
 
2110 1165
 int
2111
-bg_freeunmarked(bg_t *bg)
1166
+imutil_aspectmaximize(int w, int h, int maxw, int maxh, int *neww, int *newh)
2112 1167
 {
2113
-        int i;
2114
-        bgload_t *bgload;
2115
-        if(bg==NULL)
1168
+        if(neww==NULL || newh==NULL || w==0 || h==0 || maxw==0 || maxh==0)
2116 1169
                 return(-1);
2117
-        for(i=0,bgload=bg->bgload;i<bg->sizebgload;i++,bgload++) {
2118
-                if(bgload->lended_to_thread && bgload->thread_finished && bgload->has_mark==0) {
2119
-                        if(bgload->has_data) {
2120
-#if 1
2121
-fprintf(stderr,"bg: Unloading: \"%s\"\n",bgload->path);
2122
-#endif
2123
-                                UnloadImage(bgload->image);
2124
-                                bgload->has_data=0;
2125
-                        }
2126
-#if 1
2127
-else {
2128
-fprintf(stderr,"bg: Cancelling: \"%s\"\n",bgload->path);
2129
-}
2130
-#endif
2131
-                        memset(bgload,0,sizeof(bgload_t));
2132
-                }
1170
+        if((w/h)>(maxw/maxh) || (maxw==maxh && w>h)) {
1171
+                *neww=maxw;
1172
+                *newh=h*maxw/w;
1173
+        } else { /* (w/h)<=(maxw/maxh) */
1174
+                *newh=maxh;
1175
+                *neww=w*maxh/h;
2133 1176
         }
2134 1177
         return(0);
2135 1178
 }
2136 1179
 
2137
-void *
2138
-bg_thread(void *parambg)
2139
-{
2140
-        bg_t *bg;
2141
-        char dummy;
2142
-        bg=(bg_t *)parambg;
2143
-        int i;
2144
-        bgload_t *bgload;
2145
-        while(1) {
2146
-                mypiperead(bg->pipe[RD],&dummy,1);
2147
-#if 1
2148
-fprintf(stderr,"Thread received byte: %i\n",(int)((unsigned char)dummy));
2149
-#endif
2150
-                if(dummy!=0)
2151
-                        break; /* was told to exit */
2152
-                for(i=0,bgload=bg->bgload;i<bg->sizebgload;i++,bgload++) {
2153
-                        if(bgload->lended_to_thread==0)
2154
-                                continue;
2155
-                        if(bgload->is_todo==0) {
2156
-                                bgload->thread_finished=1;
2157
-                                continue;
2158
-                        }
2159
-                        if(bgload->has_data==0 && bgload->has_failedload==0) {
2160
-                                bgload->image=imutil_loadimage(bgload->path);
2161
-                                if(IsImageValid(bgload->image))
2162
-                                        bgload->has_data=1;
2163
-                                else
2164
-                                        bgload->has_failedload=1;
2165
-                                bgload->thread_finished=1;
2166
-                        }
2167
-                }
2168
-        }
2169
-        pthread_exit(NULL);
2170
-        return(NULL);
2171
-}
2172
-
2173
-#if !defined(__linux__) && !defined(ANDROID)
2174
-static int
2175
-mypipe(int fds[2])
2176
-{
2177
-        return(win32pipe_pipe(fds));
2178
-}
2179
-
2180
-static int
2181
-mypiperead(int fd, char *buf, int count)
2182
-{
2183
-        return(win32pipe_read(fd,buf,count));
2184
-}
2185
-
2186
-static int
2187
-mypipewrite(int fd, char *buf, int count)
2188
-{
2189
-        return(win32pipe_write(fd,buf,count));
2190
-}
2191
-#else
2192
-static int
2193
-mypipe(int fds[2])
2194
-{
2195
-        return(pipe(fds));
2196
-}
2197
-
2198
-static int
2199
-mypiperead(int fd, char *buf, int count)
2200
-{
2201
-        return(read(fd,buf,count));
2202
-}
2203
-
2204
-static int
2205
-mypipewrite(int fd, char *buf, int count)
2206
-{
2207
-        return(write(fd,buf,count));
2208
-}
2209
-#endif
2210
-
2211
-
2212 1180
new file mode 100644
... ...
@@ -0,0 +1,760 @@
1
+/*
2
+ * rayui.c
3
+ *
4
+ * Collections of functions to aid creating GUIs using raylib
5
+ *
6
+ * History:
7
+ *      20250902 Creation from imgmover prototype.
8
+ *      20250920 Reimplemented all scroll functionality.
9
+ *
10
+ * Author: Dario Rodriguez dario@darionomono.com
11
+ * (c) Dario Rodriguez 2025
12
+ * This program is licensed under the terms of GNU GPL v2.1+
13
+ */
14
+
15
+#include <stdio.h>
16
+#include <stdlib.h>
17
+#include <unistd.h>
18
+#include <string.h>
19
+#include <stdarg.h>
20
+#include <sys/time.h>
21
+#include "raylib.h"
22
+#include "rayui.h"
23
+#include "roboto_regular.c"
24
+
25
+#define DEFAULTTARGETFPS 30
26
+#if defined(ANDROID) || defined(SIMANDROID)
27
+#define FONTSIZE 64
28
+#define FONTBIGSIZE 96
29
+#define FONTHUGESIZE 128
30
+#else
31
+#define FONTSIZE 18
32
+#define FONTBIGSIZE 32
33
+#define FONTHUGESIZE 48
34
+#endif
35
+
36
+#if !defined(__linux__) && !defined(ANDROID) && RAYLIB_VERSION_MAJOR==5 && RAYLIB_VERSION_MINOR==0
37
+/* the old raylib used in the windows build lacks this function */
38
+bool IsImageValid(Image image)
39
+{
40
+    bool result = false;
41
+
42
+    if ((image.data != NULL) &&     // Validate pixel data available
43
+        (image.width > 0) &&        // Validate image width
44
+        (image.height > 0) &&       // Validate image height
45
+        (image.format > 0) &&       // Validate image format
46
+        (image.mipmaps > 0)) result = true; // Validate image mipmaps (at least 1 for basic mipmap level)
47
+
48
+    return result;
49
+}
50
+#endif
51
+
52
+menubar_t *rayuimenubar_init(char *menus, font_t *font);
53
+void rayuimenubar_free(menubar_t *menubar);
54
+
55
+int rayuimenubar_mouse(menubar_t *menubar, Vector2 mousepos, int lmbpressed, int lmbreleased, int lmbdown, int *click_avail, char **sel_menu, char **sel_submenu);
56
+int rayuimenubar_draw(menubar_t *menubar, int windowwidth, int windowheight, int *needs_nextredraw);
57
+
58
+static int *intglobal_getcodepoints(int *sizecodepoints);
59
+
60
+int intglobal_menu_count(char *menus);
61
+char *intglobal_menu_get(char *menus, int targetn, int *len);
62
+int intglobal_submenu_count(char *menus);
63
+char *intglobal_submenu_get(char *menus, int targetsubn, int *len);
64
+
65
+char *intglobal_strduplen(char *str, int len);
66
+
67
+int intglobal_menudata_pos2option(menudata_t *menudata, Vector2 pos);
68
+
69
+static char *intglobal_messageboxcaption(char *newcaption);
70
+
71
+rayui_t *
72
+rayui_init(int w, int h, char *title, char *menus)
73
+{
74
+        rayui_t *rayui;
75
+        char *errstr;
76
+        if((rayui=calloc(1,sizeof(rayui_t)))==NULL) {
77
+                rayui_free(rayui),rayui=NULL;
78
+                return(NULL); /* insuf. mem. */
79
+        }
80
+        rayui->defaultfontdata=(const unsigned char *)roboto_regular;
81
+        rayui->sizedefaultfontdata=sizeof(roboto_regular)-1;
82
+        /* init window */
83
+        SetTraceLogLevel(LOG_ERROR);
84
+        InitWindow((rayui->w=w),(rayui->h=h),(title==NULL)?"rayui":title);
85
+        rayui->windowinit=1;
86
+        SetTargetFPS(DEFAULTTARGETFPS);
87
+        rayui->targetfps=DEFAULTTARGETFPS;
88
+        /* init fonts and contents */
89
+        if(title!=NULL)
90
+                intglobal_messageboxcaption(title);
91
+        if((errstr="Couldn't init font")==NULL
92
+          || (rayui->font=rayuifont_init(FONTSIZE))==NULL
93
+          || (rayui->fontbig=rayuifont_init(FONTBIGSIZE))==NULL
94
+          || (rayui->fonthuge=rayuifont_init(FONTHUGESIZE))==NULL
95
+          || (errstr="Couldn't init menus")==NULL
96
+          || (menus!=NULL && (rayui->menubar=rayuimenubar_init(menus,rayui->font))==NULL)
97
+        ) {
98
+                global_messagebox("%s",errstr);
99
+                rayui_free(rayui),rayui=NULL;
100
+                return(NULL); /* insuf. mem. */
101
+        }
102
+        return(rayui);
103
+}
104
+
105
+void
106
+rayui_free(rayui_t *rayui)
107
+{
108
+        if(rayui==NULL)
109
+                return;
110
+        if(rayui->menubar!=NULL)
111
+                rayuimenubar_free(rayui->menubar),rayui->menubar=NULL;
112
+        if(rayui->font!=NULL)
113
+                rayuifont_free(rayui->font),rayui->font=NULL;
114
+        if(rayui->fontbig!=NULL)
115
+                rayuifont_free(rayui->fontbig),rayui->fontbig=NULL;
116
+        if(rayui->fonthuge!=NULL)
117
+                rayuifont_free(rayui->fonthuge),rayui->fonthuge=NULL;
118
+        if(rayui->windowinit)
119
+                CloseWindow(),rayui->windowinit=0;
120
+        free(rayui),rayui=NULL;
121
+        return;
122
+}
123
+
124
+
125
+int
126
+rayui_scrollablerectreset(rayui_t *rayui, mousedata_t *mousedata)
127
+{
128
+        if(rayui==NULL || mousedata==NULL)
129
+                return(-1);
130
+        mousedata->usedscrollablerect=0;
131
+        return(0);
132
+}
133
+
134
+int
135
+rayui_scrollablerectadd(rayui_t *rayui, mousedata_t *mousedata,whxy_t *rect, char *id, int scrollpos, int (*tryselect)(void *userptr, Vector2 mousepos),void *userptr, int scrollthreshold)
136
+{
137
+        scrollrect_t *scrollrect;
138
+        if(rayui==NULL || mousedata==NULL || rect==NULL || id==NULL)
139
+                return(-1);
140
+        if(mousedata->usedscrollablerect==MAXSCROLLABLERECT)
141
+                return(-1);
142
+        scrollrect=mousedata->scrollablerect+mousedata->usedscrollablerect;
143
+        memcpy(&(scrollrect->whxy),rect,sizeof(whxy_t));
144
+        strncpy(scrollrect->id,id,SIZESCROLLABLERECTID);
145
+        scrollrect->id[sizeof(scrollrect->id)-1]='\0';
146
+        scrollrect->scrollpos=scrollpos;
147
+        scrollrect->tryselect=tryselect;
148
+        scrollrect->userptr=userptr;
149
+        scrollrect->scrollthreshold=scrollthreshold;
150
+        mousedata->usedscrollablerect++;
151
+        return(0);
152
+}
153
+
154
+int
155
+rayui_getmousedata(rayui_t *rayui, mousedata_t *mousedata)
156
+{
157
+        int i;
158
+        if(rayui==NULL || mousedata==NULL)
159
+                return(-1);
160
+        mousedata->oldmousepos=mousedata->mousepos;
161
+        mousedata->mousepos=GetMousePosition();
162
+        mousedata->wheel=GetMouseWheelMoveV();
163
+        mousedata->lmbpressed=IsMouseButtonPressed(0);
164
+        mousedata->lmbreleased=IsMouseButtonReleased(0);
165
+        mousedata->oldlmbdown=mousedata->lmbdown;
166
+        mousedata->lmbdown=IsMouseButtonDown(0);
167
+        mousedata->oldrmbdown=mousedata->rmbdown;
168
+        mousedata->rmbdown=IsMouseButtonDown(1);
169
+        mousedata->click_avail=1;
170
+        mousedata->has_mousechanges=(mousedata->lmbdown!=mousedata->oldlmbdown
171
+            || mousedata->rmbdown!=mousedata->oldrmbdown
172
+            || mousedata->mousepos.x!=mousedata->oldmousepos.x
173
+            || mousedata->mousepos.y!=mousedata->oldmousepos.y
174
+            || mousedata->wheel.x!=0
175
+            || mousedata->wheel.y!=0
176
+          )?1:0;
177
+        mousedata->needs_nextredraw=0;
178
+        /* mouse process scrolling */
179
+        if(mousedata->lmbdown==1 && mousedata->oldlmbdown==0 && mousedata->scrollstart==0) {
180
+                for(i=0;i<mousedata->usedscrollablerect;i++) {
181
+                        if(is_global_insidewhxy(mousedata->mousepos,&(mousedata->scrollablerect[i].whxy),0)) {
182
+                                strncpy(mousedata->scrollingid,mousedata->scrollablerect[i].id,sizeof(mousedata->scrollingid));
183
+                                mousedata->scrollingid[sizeof(mousedata->scrollingid)-1]='\0';
184
+                                mousedata->scrollstart=global_currentmilliseconds();
185
+                                mousedata->scrollstartpos=mousedata->mousepos;
186
+                                mousedata->scrollposstart=mousedata->scrollablerect[i].scrollpos;
187
+                                break;
188
+                        }
189
+                }
190
+        }
191
+        if(mousedata->scrollstart!=0 && mousedata->lmbdown==0) {
192
+                mousedata->scrollstart=0;
193
+                if(mousedata->is_scrolling)
194
+                        mousedata->click_avail=0; /* this click is the mouseup of the scroll */
195
+        }
196
+        mousedata->is_scrolling=(mousedata->scrollstart==0)?0:mousedata->is_scrolling;
197
+        if(mousedata->is_scrolling==0 && mousedata->scrollstart!=0) {
198
+                for(i=0;i<mousedata->usedscrollablerect;i++) {
199
+                        if(is_global_insidewhxy(mousedata->mousepos,&(mousedata->scrollablerect[i].whxy),0) && mousedata->scrollablerect[i].tryselect!=NULL) {
200
+                                float t;
201
+                                t=mousedata->scrollstartpos.y-mousedata->mousepos.y;
202
+                                t=(t<0)?-t:t;
203
+                                if(t>mousedata->scrollablerect[i].scrollthreshold) {
204
+                                        mousedata->is_scrolling=1;
205
+                                        mousedata->scrolllast=0;
206
+                                }
207
+                                t=mousedata->scrollstartpos.x-mousedata->mousepos.x;
208
+                                t=(t<0)?-t:t;
209
+                                if(t>mousedata->scrollablerect[i].scrollthreshold) {
210
+                                        mousedata->is_scrolling=0,mousedata->scrollstart=0;
211
+                                        if(mousedata->scrollablerect[i].tryselect(mousedata->scrollablerect[i].userptr,mousedata->mousepos)!=-1) {
212
+                                                mousedata->click_avail=0;
213
+                                                break;
214
+                                        }
215
+                                }
216
+                        }
217
+                }
218
+        }
219
+        if(mousedata->is_scrolling) {
220
+                long long tcur,tdif;
221
+                long long ycur;
222
+                tcur=global_currentmilliseconds();
223
+                tdif=tcur-mousedata->scrolllast;
224
+                ycur=mousedata->scrollstartpos.y-mousedata->mousepos.y;
225
+                mousedata->scrollspeed=(tdif>0)?(mousedata->oldmousepos.y-mousedata->mousepos.y)*100000/tdif:0;
226
+                mousedata->scrollpos=mousedata->scrollposstart+ycur;
227
+                mousedata->scrolllast=tcur;
228
+        }
229
+        if(mousedata->is_scrolling==0 && mousedata->scrollspeed!=0) {
230
+                mousedata->scrollspeed=mousedata->scrollspeed*4/5;
231
+                mousedata->scrollpos+=mousedata->scrollspeed;
232
+        }
233
+        return(0);
234
+}
235
+
236
+int
237
+is_rayui_scrolling(rayui_t *rayui, mousedata_t *mousedata,char *id, int *newscrollpos)
238
+{
239
+        if(rayui==NULL || mousedata==NULL || id==NULL || newscrollpos==NULL)
240
+                return(0);
241
+        if((mousedata->is_scrolling || mousedata->scrollspeed!=0) && strcmp(mousedata->scrollingid,id)==0) {
242
+                *newscrollpos=mousedata->scrollpos;
243
+                return(1);
244
+        }
245
+        return(0);
246
+}
247
+
248
+void
249
+rayui_settargetfps(rayui_t *rayui, int newfps)
250
+{
251
+        if(rayui==NULL)
252
+                return;
253
+        newfps=(newfps<=0)?DEFAULTTARGETFPS:newfps;
254
+        rayui->targetfps=newfps;
255
+        SetTargetFPS(newfps);
256
+        return;
257
+}
258
+
259
+int
260
+has_rayui_timeleft(rayui_t *rayui)
261
+{
262
+        struct timeval *deadline,now;
263
+        if(rayui==NULL)
264
+                return(1);
265
+        deadline=&(rayui->deadline);
266
+        gettimeofday(&now,NULL);
267
+        if(deadline->tv_sec<now.tv_sec || (deadline->tv_sec==now.tv_sec && deadline->tv_usec<now.tv_usec))
268
+                return(0);
269
+        return(1);
270
+}
271
+
272
+void
273
+rayui_timereset(rayui_t *rayui)
274
+{
275
+        struct timeval *deadline;
276
+        long deadlineincr;
277
+        if(rayui==NULL)
278
+                return;
279
+        deadline=&(rayui->deadline);
280
+        gettimeofday(deadline,NULL);
281
+        deadlineincr=1000000L/((rayui->targetfps!=0)?rayui->targetfps:DEFAULTTARGETFPS);
282
+        deadline->tv_usec+=deadlineincr;
283
+        deadline->tv_sec+=(deadline->tv_usec)/1000000L;
284
+        deadline->tv_usec%=1000000L;
285
+}
286
+
287
+
288
+long long
289
+global_currentmilliseconds(void)
290
+{
291
+        long long res;
292
+        struct timeval now;
293
+        gettimeofday(&now,NULL);
294
+        res=((long long) (now.tv_sec))*1000000L+((long long) (now.tv_usec));
295
+        return(res);
296
+}
297
+
298
+font_t *
299
+rayuifont_init(int size)
300
+{
301
+        font_t *font;
302
+        int sizecodepoints;
303
+        int *codepoints;
304
+        if((font=calloc(1,sizeof(font_t)))==NULL)
305
+                return(NULL); /* insuf. mem. */
306
+        font->height=size;
307
+        codepoints=intglobal_getcodepoints(&sizecodepoints);
308
+        font->font=LoadFontFromMemory(".ttf",(const unsigned char *)roboto_regular,sizeof(roboto_regular)-1,font->height,codepoints,sizecodepoints);
309
+        return(font);
310
+}
311
+
312
+void
313
+rayuifont_free(font_t *font)
314
+{
315
+        if(font==NULL)
316
+                return;
317
+        /* NOTE: Cannot call UnloadFont(font->font) as the data was not malloc'd; see https://github.com/raysan5/raylib/blob/master/examples/others/embedded_files_loading.c */
318
+        free(font),font=NULL;
319
+        return;
320
+}
321
+
322
+menubar_t *
323
+rayuimenubar_init(char *menus, font_t *font)
324
+{
325
+        int i,j;
326
+        char *str,*substr;
327
+        int len,sublen;
328
+        menubar_t *menubar;
329
+        menudata_t *menudata;
330
+        if(menus==NULL || font==NULL)
331
+                return(NULL); /* sanity check failed */
332
+        if((menubar=calloc(1,sizeof(menubar_t)))==NULL
333
+          || (menubar->sizemenudata=intglobal_menu_count(menus))<=0
334
+          || (menubar->menudata=calloc(menubar->sizemenudata,sizeof(menudata_t)))==NULL
335
+        ) {
336
+                rayuimenubar_free(menubar),menubar=NULL;
337
+                return(NULL); /* insuf. mem. */
338
+        }
339
+        menubar->ptrfont=font;
340
+        menubar->height=font->height+font->height/2;
341
+        /* init menus */
342
+        for(i=0;i<menubar->sizemenudata;i++) {
343
+                if((menudata=menubar->menudata[i]=calloc(1,sizeof(menudata_t)))==NULL
344
+                  || (str=intglobal_menu_get(menus,i,&len))==NULL
345
+                  || (menudata->title=intglobal_strduplen(str,len))==NULL
346
+                  || (menudata->sizeoptions=intglobal_submenu_count(str))<=0
347
+                  || (menudata->options=calloc(menudata->sizeoptions,sizeof(char *)))==NULL
348
+                ) {
349
+                        rayuimenubar_free(menubar),menubar=NULL;
350
+                        return(NULL); /* insuf. mem. */
351
+                }
352
+                for(j=0;j<menudata->sizeoptions;j++) {
353
+                        if((substr=intglobal_submenu_get(str,j,&sublen))==NULL
354
+                          || (menudata->options[j]=intglobal_strduplen(substr,sublen))==NULL
355
+                        ) {
356
+                                rayuimenubar_free(menubar),menubar=NULL;
357
+                                return(NULL); /* insuf. mem. */
358
+                        }
359
+                }
360
+        }
361
+        return(menubar);
362
+}
363
+
364
+void
365
+rayuimenubar_free(menubar_t *menubar)
366
+{
367
+        int i,j;
368
+        menudata_t *menudata;
369
+        if(menubar==NULL)
370
+                return;
371
+        if(menubar->menudata!=NULL) {
372
+                for(i=0;i<menubar->sizemenudata;i++) {
373
+                        if((menudata=menubar->menudata[i])==NULL)
374
+                                continue;
375
+                        if(menudata->title!=NULL)
376
+                                free(menudata->title),menudata->title=NULL;
377
+                        if(menudata->options!=NULL) {
378
+                                for(j=0;j<menudata->sizeoptions;j++) {
379
+                                        if(menudata->options[j]!=NULL)
380
+                                                free(menudata->options[j]),menudata->options[j]=NULL;
381
+                                }
382
+                                free(menudata->options),menudata->options=NULL,menudata->sizeoptions=0;
383
+                        }
384
+                        free(menubar->menudata[i]),menubar->menudata[i]=NULL,menudata=NULL;
385
+                }
386
+                free(menubar->menudata),menubar->menudata=NULL,menubar->sizemenudata=0;
387
+        }
388
+        free(menubar),menubar=NULL;
389
+        return;
390
+}
391
+
392
+int
393
+rayuimenubar_mouse(menubar_t *menubar, Vector2 mousepos, int lmbpressed, int lmbreleased, int lmbdown, int *click_avail, char **sel_menu, char **sel_submenu)
394
+{
395
+        int flag_outsideall;
396
+        int i,j;
397
+        if(menubar==NULL || click_avail==NULL || sel_menu==NULL || sel_submenu==NULL)
398
+                return(-1);
399
+        *click_avail=1;
400
+        *sel_menu=NULL;
401
+        *sel_submenu=NULL;
402
+        flag_outsideall=1;
403
+#if 0
404
+if(lmbpressed || lmbdown)
405
+ fprintf(stderr,"in_menubar_mouse: lmbpressed:%i lmbdown:%i\n",lmbpressed,lmbdown);
406
+#endif
407
+        for(i=0;i<menubar->sizemenudata;i++) {
408
+                int insidetitle,currentoption;
409
+                insidetitle=is_global_insidewhxy(mousepos,&(menubar->menudata[i]->whxy),0);
410
+                currentoption=intglobal_menudata_pos2option(menubar->menudata[i],mousepos);
411
+                flag_outsideall=(currentoption!=-1 || insidetitle)?0:flag_outsideall;
412
+                if(lmbreleased && insidetitle) {
413
+                        for(j=0;j<menubar->sizemenudata;j++) {
414
+                                menubar->menudata[j]->flag_stickyopen=(j==i)?1:0;
415
+                                menubar->menudata[j]->flag_open=0;
416
+                                menubar->menudata[j]->currentoption=-1;
417
+                        }
418
+                } else if((lmbpressed || lmbdown) && insidetitle) {
419
+                        for(j=0;j<menubar->sizemenudata;j++) {
420
+                                menubar->menudata[j]->flag_open=(j==i)?1:0;
421
+                                menubar->menudata[j]->flag_stickyopen=0;
422
+                                menubar->menudata[j]->currentoption=-1;
423
+                        }
424
+                } else if((lmbdown || menubar->menudata[i]->flag_stickyopen) && currentoption!=-1) {
425
+                        for(j=0;j<menubar->sizemenudata;j++) {
426
+                                if(lmbreleased==0 || j!=i || menubar->menudata[i]->flag_stickyopen==0) {
427
+                                        menubar->menudata[j]->flag_open=(j==i)?menubar->menudata[i]->flag_open:0;
428
+                                        menubar->menudata[j]->flag_stickyopen=(j==i)?menubar->menudata[i]->flag_stickyopen:0;
429
+                                        menubar->menudata[j]->currentoption=(j==i)?currentoption:-1;
430
+                                } else {
431
+                                        menubar->menudata[j]->flag_open=0;
432
+                                        menubar->menudata[j]->flag_stickyopen=0;
433
+                                        menubar->menudata[j]->currentoption=-1;
434
+                                        /* has selected this submenu */
435
+                                        *click_avail=0;
436
+                                        *sel_menu=menubar->menudata[j]->title;
437
+                                        *sel_submenu=menubar->menudata[j]->options[currentoption];
438
+                                }
439
+                        }
440
+                } else if(menubar->menudata[i]->flag_stickyopen && currentoption==-1) {
441
+                        if(lmbreleased) {
442
+                                menubar->menudata[i]->flag_open=0;
443
+                                menubar->menudata[i]->flag_stickyopen=0;
444
+                        }
445
+                        menubar->menudata[i]->currentoption=-1;
446
+                } else if(lmbreleased && currentoption!=-1) {
447
+                        for(j=0;j<menubar->sizemenudata;j++) {
448
+                                menubar->menudata[j]->flag_open=0;
449
+                                menubar->menudata[j]->flag_stickyopen=0;
450
+                                menubar->menudata[j]->currentoption=-1;
451
+                        }
452
+                        /* has selected this submenu */
453
+                        *click_avail=0;
454
+                        *sel_menu=menubar->menudata[i]->title;
455
+                        *sel_submenu=menubar->menudata[i]->options[currentoption];
456
+                } else if(lmbdown==0) {
457
+                        menubar->menudata[i]->flag_open=0;
458
+                        menubar->menudata[i]->flag_stickyopen=0;
459
+                        menubar->menudata[i]->currentoption=-1;
460
+                }
461
+        }
462
+        if(flag_outsideall) {
463
+                for(j=0;j<menubar->sizemenudata;j++) {
464
+                        menubar->menudata[j]->currentoption=-1;
465
+                }
466
+        }
467
+        /* update click_avail */
468
+        for(j=0;j<menubar->sizemenudata;j++) {
469
+                if(menubar->menudata[j]->flag_open || menubar->menudata[j]->flag_stickyopen) {
470
+                        *click_avail=0;
471
+                        break;
472
+                }
473
+        }
474
+        return(0);
475
+}
476
+
477
+int
478
+rayuimenubar_draw(menubar_t *menubar, int windowwidth, int windowheight, int *needs_nextredraw)
479
+{
480
+        int i,j,k,x;
481
+        menudata_t *menudata;
482
+        font_t *font;
483
+        if(menubar==NULL)
484
+                return(-1); /* sanity check failed */
485
+        font=menubar->ptrfont;
486
+        DrawRectangle(0,0,windowwidth, font->height+font->height/2, (Color){ 235, 235, 235, 235 } );
487
+        for(i=0,x=0;i<menubar->sizemenudata;i++) {
488
+                Vector2 v2;
489
+                menudata=menubar->menudata[i];
490
+                v2=MeasureTextEx(font->font,menudata->title,font->height,0);
491
+                FILLWHXY(menudata->whxy,((int)v2.x)+font->height,font->height+font->height/2,x,0);
492
+                v2.x=(float) (menudata->whxy.x+font->height/2);
493
+                v2.y=(float) (menudata->whxy.y+font->height/4);
494
+                DrawTextEx(font->font
495
+                  ,menudata->title
496
+                  ,v2
497
+                  ,font->height
498
+                  ,0
499
+                  ,(Color){ 45, 45, 45, 255 }
500
+                );
501
+                if(menudata->flag_open || menudata->flag_stickyopen) {
502
+                        int underline_height=3;
503
+                        int maxw;
504
+                        DrawRectangle(menudata->whxy.x,menudata->whxy.y+menudata->whxy.h-underline_height,menudata->whxy.w,underline_height, (Color){ 53,132,228,255 } );
505
+                        for(j=0,maxw=0;j<menudata->sizeoptions;j++) {
506
+                                v2=MeasureTextEx(font->font,menudata->options[j],font->height,0);
507
+                                maxw=(((int)(v2.x))>maxw)?((int)(v2.x)):maxw;
508
+                        }
509
+                        maxw=(maxw<(menudata->whxy.w+font->height))?(menudata->whxy.w+font->height):maxw;
510
+                        maxw+=font->height;
511
+                        FILLWHXY(menudata->optionswhxy,maxw,(font->height+font->height/2)*menudata->sizeoptions,menudata->whxy.x+1,menudata->whxy.y+menudata->whxy.h+2);
512
+                        DrawLine(menudata->optionswhxy.x-1,menudata->optionswhxy.y-2,menudata->optionswhxy.x+menudata->optionswhxy.w+2,menudata->optionswhxy.y-2,(Color){ 255,255,255,255 } );
513
+                        DrawLine(menudata->optionswhxy.x-1,menudata->optionswhxy.y,menudata->optionswhxy.x-1,menudata->optionswhxy.y+menudata->optionswhxy.h+1,(Color){ 255,255,255,255 } );
514
+                        DrawLine(menudata->optionswhxy.x+menudata->optionswhxy.w+2,menudata->optionswhxy.y,menudata->optionswhxy.x+menudata->optionswhxy.w+2,menudata->optionswhxy.y+menudata->optionswhxy.h+1,(Color){ 192,192,192,255 } );
515
+                        DrawLine(menudata->optionswhxy.x-1,menudata->optionswhxy.y+menudata->optionswhxy.h+1,menudata->optionswhxy.x+menudata->optionswhxy.w+2,menudata->optionswhxy.y+menudata->optionswhxy.h+1,(Color){ 192,192,192,255 } );
516
+                        DrawRectangle(menudata->optionswhxy.x,menudata->optionswhxy.y,menudata->optionswhxy.w,menudata->optionswhxy.h,(Color){ 235, 235, 235, 235 });
517
+                        for(k=0;k<menudata->sizeoptions;k++) {
518
+                                Color c;
519
+                                c=(k==menudata->currentoption)?((Color){ 255,255,255,255 }):((Color){ 45, 45, 45, 255 });
520
+                                if(k==menudata->currentoption)
521
+                                        DrawRectangle(menudata->optionswhxy.x+1,menudata->optionswhxy.y+(font->height+(font->height/2))*k,menudata->optionswhxy.w-2,font->height+font->height/2,(Color){ 53,132,228,255 });
522
+                                v2.x=(float) (menudata->optionswhxy.x+font->height/2);
523
+                                v2.y=(float) (menudata->optionswhxy.y+(font->height/4)+(font->height+(font->height/2))*k);
524
+                                DrawTextEx(font->font
525
+                                  ,menudata->options[k]
526
+                                  ,v2
527
+                                  ,font->height
528
+                                  ,0
529
+                                  ,c
530
+                                );
531
+                        }
532
+                } else {
533
+                        FILLWHXY(menudata->optionswhxy,0,0,0,0);
534
+                }
535
+                x=menudata->whxy.x+menudata->whxy.w;
536
+        }
537
+        return(0);
538
+}
539
+
540
+static int *
541
+intglobal_getcodepoints(int *sizecodepoints)
542
+{
543
+        static int codepoints[]={
544
+/* Basic Latin */
545
+32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
546
+/* Latin-1 Supplement */
547
+160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,
548
+/* down arrow (U+2186 -- this font doesn't have arrows, this is old roman numeral 50 */
549
+(0x21<<8)|0x86,
550
+};
551
+        if(sizecodepoints!=NULL)
552
+                *sizecodepoints=(int) (sizeof(codepoints)/sizeof(codepoints[0]));
553
+        return(codepoints);
554
+}
555
+
556
+int
557
+intglobal_menu_count(char *menus)
558
+{
559
+        int n;
560
+        char *ptr,*next;
561
+        if(menus==NULL)
562
+                return(0); /* sanity check error */
563
+        for(ptr=menus,n=0;(next=strchr(ptr,'\n'))!=NULL;ptr=next+1) {
564
+                if(next[1]=='\n') {
565
+                        next++;
566
+                        n++;
567
+                }
568
+        }
569
+        return(n);
570
+}
571
+
572
+char *
573
+intglobal_menu_get(char *menus, int targetn, int *len)
574
+{
575
+        int n;
576
+        char *ptr,*next,*end;
577
+        int is_title;
578
+        if(len!=NULL)
579
+                *len=0;
580
+        if(menus==NULL || targetn<0)
581
+                return(NULL); /* sanity check error */
582
+        end=menus+strlen(menus);
583
+        for(ptr=menus,is_title=1,n=0;(next=strchr(ptr,'\n'))!=NULL;ptr=next+1) {
584
+                if(targetn==n && is_title==1) {
585
+                        if(len!=NULL)
586
+                                *len=next-ptr;
587
+                        return(ptr); /* found, return start of menu string */
588
+                }
589
+                is_title=0;
590
+                if(next[1]=='\n') {
591
+                        n++;
592
+                        next++;
593
+                        is_title=1;
594
+                }
595
+        }
596
+        return(end); /* not found, return end of menus */
597
+}
598
+
599
+int
600
+intglobal_submenu_count(char *menus)
601
+{
602
+        int subn;
603
+        char *ptr,*next;
604
+        if(menus==NULL)
605
+                return(0); /* sanity check error */
606
+        next=strchr(menus,'\n');
607
+        if(next==NULL)
608
+                return(0); /* no title */
609
+        for(subn=0,ptr=next+1;(next=strchr(ptr,'\n'))!=NULL;ptr=next+1) {
610
+                subn++;
611
+                if(next[1]=='\n')
612
+                        break;
613
+        }
614
+        return(subn);
615
+}
616
+
617
+char *
618
+intglobal_submenu_get(char *menus, int targetsubn, int *len)
619
+{
620
+        char *ptr,*next,*end;
621
+        int subn;
622
+        if(len!=NULL)
623
+                *len=0;
624
+        if(menus==NULL || targetsubn<0)
625
+                return(NULL); /* sanity check error */
626
+        end=menus+strlen(menus);
627
+        next=strchr(menus,'\n');
628
+        if(next==NULL)
629
+                return(end); /* no title */
630
+        for(ptr=next+1,subn=0;(next=strchr(ptr,'\n'))!=NULL;ptr=next+1,subn++) {
631
+                if(targetsubn==subn) {
632
+                        if(len!=NULL)
633
+                                *len=next-ptr;
634
+                        return(ptr);
635
+                }
636
+                if(next[1]=='\n')
637
+                        break; /* "\n\n" marks the end of submenus */
638
+        }
639
+        return(end);
640
+}
641
+
642
+char *
643
+intglobal_strduplen(char *str, int len)
644
+{
645
+        char *res;
646
+        if(len<0 || (str==NULL && len!=0))
647
+                return(NULL);
648
+        if((res=malloc(len+1))==NULL)
649
+                return(NULL);
650
+        memcpy(res,str,len);
651
+        res[len]='\0';
652
+        return(res);
653
+}
654
+
655
+int
656
+intglobal_menudata_pos2option(menudata_t *menudata, Vector2 pos)
657
+{
658
+        int n,h;
659
+        if(menudata==NULL
660
+          || (menudata->flag_open==0 && menudata->flag_stickyopen==0)
661
+          || is_global_insidewhxy(pos, &(menudata->optionswhxy),0)==0
662
+        ) {
663
+                return(-1);
664
+        }
665
+        h=(menudata->sizeoptions==0)?0:menudata->optionswhxy.h/menudata->sizeoptions;
666
+        n=(((int)pos.y)-menudata->optionswhxy.y)/h;
667
+        return(n);
668
+}
669
+
670
+
671
+static char *
672
+intglobal_messageboxcaption(char *newcaption)
673
+{
674
+        static char caption[1024]={"Message"};
675
+        if(newcaption!=NULL) {
676
+                strncpy(caption,newcaption,sizeof(caption));
677
+                caption[sizeof(caption)-1]='\0';
678
+        }
679
+        return(caption);
680
+}
681
+
682
+
683
+#if !defined(__linux__) && !defined(ANDROID)
684
+int MessageBoxA(void *hWnd,void *lpText,void *lpCaption,unsigned int uType);
685
+void
686
+global_messagebox(char *format, ...)
687
+{
688
+        char msgbuf[4096];
689
+        va_list va;
690
+        va_start(va,format);
691
+        vsnprintf(msgbuf,sizeof(msgbuf),format,va);
692
+        msgbuf[sizeof(msgbuf)-1]='\0';
693
+        va_end(va);
694
+        MessageBoxA(NULL,msgbuf,intglobal_messageboxcaption(NULL),0);
695
+        return;
696
+}
697
+#else
698
+void
699
+global_messagebox(char *format, ...)
700
+{
701
+        va_list va;
702
+        va_start(va,format);
703
+        vfprintf(stderr,format,va);
704
+        fprintf(stderr,"\n");
705
+        va_end(va);
706
+        return;
707
+}
708
+#endif
709
+
710
+#ifdef ANDROID
711
+Image
712
+global_loadimage(const char *filename)
713
+{
714
+        unsigned char *filedata=NULL;
715
+        FILE *f=NULL;
716
+        struct stat st;
717
+        Image img;
718
+        char *ext;
719
+        if((f=fopen(filename,"r"))==NULL
720
+          || fstat(fileno(f),&st)!=0
721
+          || st.st_size<=0
722
+          || (filedata=(unsigned char *)malloc(st.st_size))==NULL
723
+          || fread(filedata,1,st.st_size,f)!=st.st_size
724
+        ) {
725
+                if(f!=NULL)
726
+                        fclose(f),f=NULL;
727
+                if(filedata!=NULL)
728
+                        free(filedata),filedata=NULL;
729
+                return((Image){0});
730
+        }
731
+        fclose(f);
732
+        ext=strchr(filename,'.');
733
+        ext=(ext==NULL)?filename+strlen(filename):ext;
734
+        img=LoadImageFromMemory(ext,filedata,st.st_size);
735
+        free(filedata),filedata=NULL;
736
+        return(img);
737
+}
738
+#else
739
+Image
740
+global_loadimage(const char *filename)
741
+{
742
+        return(LoadImage(filename));
743
+}
744
+#endif
745
+
746
+int
747
+is_global_insidewhxy(Vector2 pos, whxy_t *whxy, int margin)
748
+{
749
+        if(whxy==NULL)
750
+                return(0); /* sanity check error */
751
+        if(pos.x>=(float)(whxy->x-margin)
752
+          && pos.x<=(float)(whxy->x+whxy->w+margin)
753
+          && pos.y>=(float)(whxy->y-margin)
754
+          && pos.y<=(float)(whxy->y+whxy->h+margin)
755
+        ) {
756
+                return(1);
757
+        }
758
+        return(0);
759
+}
760
+
0 761
new file mode 100644
... ...
@@ -0,0 +1,159 @@
1
+/*
2
+ * rayui.h
3
+ *
4
+ * Collections of functions to aid creating GUIs using raylib
5
+ *
6
+ * HEADER FILE
7
+ *
8
+ * History:
9
+ *      20250902 Creation from imgmover prototype.
10
+ *
11
+ * Author: Dario Rodriguez dario@darionomono.com
12
+ * (c) Dario Rodriguez 2025
13
+ * This program is licensed under the terms of GNU GPL v2.1+
14
+ */
15
+
16
+
17
+#ifndef RAYUI_H
18
+#define RAYUI_H
19
+
20
+#include "raylib.h"
21
+
22
+#ifndef FILLXY
23
+#define FILLXY(whxy,valx,valy) (whxy).x=(valx),(whxy).y=(valy)
24
+#endif
25
+
26
+#ifndef FILLWH
27
+#define FILLWH(whxy,valw,valh) (whxy).w=(valw),(whxy).h=(valh)
28
+#endif
29
+
30
+#ifndef FILLWHXY
31
+#define FILLWHXY(whxy,valw,valh,valx,valy) (whxy).w=(valw),(whxy).h=(valh),(whxy).x=(valx),(whxy).y=(valy)
32
+#endif
33
+
34
+#ifndef UNROLLWHXY
35
+#define UNROLLWHXY(whxy) (whxy).w,(whxy).h,(whxy).x,(whxy).y
36
+#endif
37
+
38
+#ifndef RD
39
+#define RD 0
40
+#endif
41
+
42
+#ifndef WR
43
+#define WR 1
44
+#endif
45
+
46
+#define MAXSCROLLABLERECT 8
47
+#define SIZESCROLLABLERECTID 16
48
+
49
+typedef struct whxy_t {
50
+        int w;
51
+        int h;
52
+        int x;
53
+        int y;
54
+} whxy_t;
55
+
56
+typedef struct font_t {
57
+        Font font;
58
+        int height;
59
+} font_t;
60
+
61
+typedef struct menudata_t {
62
+        char *title;
63
+        whxy_t whxy;
64
+        int sizeoptions;
65
+        char **options;
66
+        whxy_t optionswhxy;
67
+        int flag_open;
68
+        int flag_stickyopen;
69
+        int currentoption;
70
+} menudata_t;
71
+
72
+typedef struct menubar_t {
73
+        int height;
74
+        int sizemenudata;
75
+        menudata_t **menudata;
76
+        font_t *ptrfont;
77
+} menubar_t;
78
+
79
+typedef struct rayui_t {
80
+        int w;
81
+        int h;
82
+        int windowinit;
83
+        menubar_t *menubar;
84
+        const unsigned char *defaultfontdata;
85
+        int sizedefaultfontdata;
86
+        font_t *font;
87
+        font_t *fontbig;
88
+        font_t *fonthuge;
89
+        struct timeval deadline;
90
+        int targetfps;
91
+} rayui_t;
92
+
93
+typedef struct scrollrect_t {
94
+        whxy_t whxy;
95
+        char id[SIZESCROLLABLERECTID];
96
+        int scrollpos;
97
+        int (*tryselect)(void *, Vector2);
98
+        void *userptr;
99
+        int scrollthreshold;
100
+} scrollrect_t;
101
+
102
+typedef struct mousedata_t {
103
+        Vector2 oldmousepos;
104
+        Vector2 mousepos;
105
+        Vector2 wheel;
106
+        int lmbpressed;
107
+        int lmbreleased;
108
+        int oldlmbdown;
109
+        int lmbdown;
110
+        int oldrmbdown;
111
+        int rmbdown;
112
+        int click_avail;
113
+        int has_mousechanges;
114
+        int needs_nextredraw;
115
+        int is_scrolling;
116
+        char scrollingid[SIZESCROLLABLERECTID];
117
+        int scrollspeed;
118
+        long long scrollstart;
119
+        long long scrolllast;
120
+        Vector2 scrollstartpos;
121
+        int scrollposstart;
122
+        int scrollpos;
123
+        int usedscrollablerect;
124
+        scrollrect_t scrollablerect[MAXSCROLLABLERECT];
125
+} mousedata_t;
126
+
127
+rayui_t *rayui_init(int w, int h, char *title, char *menus);
128
+void rayui_free(rayui_t *rayui);
129
+
130
+int rayui_scrollablerectreset(rayui_t *rayui, mousedata_t *mousedata);
131
+int rayui_scrollablerectadd(rayui_t *rayui, mousedata_t *mousedata,whxy_t *rect, char *id, int scrollpos, int (*tryselect)(void *userptr, Vector2 mousepos),void *userptr, int scrollthreshold);
132
+int rayui_getmousedata(rayui_t *rayui, mousedata_t *mousedata);
133
+int is_rayui_scrolling(rayui_t *rayui, mousedata_t *mousedata,char *id, int *newscrollpos); /* newscrollpos is filled if it returns true */
134
+
135
+menubar_t *rayuimenubar_init(char *menus, font_t *font);
136
+void rayuimenubar_free(menubar_t *menubar);
137
+int rayuimenubar_mouse(menubar_t *menubar, Vector2 mousepos, int lmbpressed, int lmbreleased, int lmbdown, int *click_avail, char **sel_menu, char **sel_submenu);
138
+int rayuimenubar_draw(menubar_t *menubar, int windowwidth, int windowheight, int *needs_nextredraw);
139
+
140
+void rayui_settargetfps(rayui_t *rayui, int newfps);
141
+int has_rayui_timeleft(rayui_t *rayui);
142
+void rayui_timereset(rayui_t *rayui);
143
+long long global_currentmilliseconds(void);
144
+
145
+font_t *rayuifont_init(int size);
146
+void rayuifont_free(font_t *font);
147
+
148
+#ifndef __GNUC__
149
+void global_messagebox(char *format, ...);
150
+#else
151
+        void global_messagebox(char *format, ...) __attribute__ ((format (printf,1,2)));
152
+#endif
153
+Image global_loadimage(const char *filename);
154
+
155
+int is_global_insidewhxy(Vector2 pos, whxy_t *whxy, int margin);
156
+
157
+
158
+
159
+#endif