Skip to content

Commit 68d210a

Browse files
committed
FEAT: introducing _native GOB widgets_ for Windows OS.
It's just an initial _proof of concept_. Using the existing `gob!` type as a holder of native GUI widgets. At this moment there are *partially* supported these native widgets: `button`, `check`, `radio`, `group-box`, `field`, `area`, `text`, `slider` and `date-time` (which so far works more like a date picker only). Known issues: * the native widgets are not converted to image, when using `to-image window-gob`. * it looks there is a memory leak in the compositor as opening/closing multiple windows has growing memory effect. This is probably not directly related to native widgets as I can see it with just an image too. * it's possible to append widgets into another widget's `pane`, but the position is not relative to the parent. * there is no helper for creating a native gobs tree (no `layout`). * there are still some output logs as this is really more just an experiment (and my learning playground). Simple example displaying field and a button with event handler: ``` handle-events [ name: 'gob-example priority: 60 handler: func [event][ print ["view-event:" event/type event/offset event/gob] if switch event/type [ close [true] key [event/key = escape] ] [ unhandle-events self unview event/window return none ] switch event/type [ click change [ print ["Field data:" mold fld/data] ] ] none ] ] btn: make gob! [size: 200x29 offset: 20x20 widget: [button "hello"]] fld: make gob! [size: 200x29 offset: 20x50 widget: [field "world"]] win: make gob! [size: 240x99 offset: 90x99 pane: [btn fld]] view/as-is win ```
1 parent 3f182e9 commit 68d210a

19 files changed

+679
-86
lines changed

make/msvc/Make-vs-project.r3

+19-3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ VS: context [
2020

2121
SourcePath: ""
2222

23-
AdditionalDependencies: "wsock32.lib;comdlg32.lib;"
23+
AdditionalDependencies: rejoin [
24+
"wsock32.lib;comdlg32.lib;"
25+
"winmm.lib;" ;- for MIDI
26+
"Gdi32.lib;Comctl32.lib;UxTheme.lib;" ;- for View
27+
]
2428

2529
Sources: []
2630

@@ -448,8 +452,20 @@ vs/Sources: compose/only [
448452
]
449453
vs/IncludePath-x86:
450454
vs/IncludePath-x64: "..\..\..\src\include;"
451-
vs/PreprocessorDefinitions-x86: {TO_WIN32;REB_CORE;REB_EXE;ENDIAN_LITTLE;_FILE_OFFSET_BITS=64;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;USE_LZMA;}
452-
vs/PreprocessorDefinitions-x64: {UNICODE;_UNICODE;ENDIAN_LITTLE;_CRT_SECURE_NO_WARNINGS;USE_MIDI_DEVICE;USE_PNG_CODEC;USE_JPG_CODEC;USE_LZMA;REB_EXE;TEST_EXTENSIONS;_DEBUG;NO_COMPOSITOR;TO_WIN32_X64;__LLP64__;_FILE_OFFSET_BITS=64;}
455+
456+
common-definitions: {REB_EXE;ENDIAN_LITTLE;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;_FILE_OFFSET_BITS=64;}
457+
optional-components: {USE_MIDI_DEVICE;USE_PNG_CODEC;USE_JPG_CODEC;USE_LZMA;} ;TEST_EXTENSIONS;
458+
vs/PreprocessorDefinitions-x86: rejoin [
459+
common-definitions
460+
{TO_WIN32;}
461+
optional-components
462+
]
463+
vs/PreprocessorDefinitions-x64: rejoin [
464+
common-definitions
465+
{TO_WIN32_X64;__LLP64__;}
466+
optional-components
467+
]
468+
453469
vs/Prebuild-x86: {
454470
set REBOL=..\..\prebuild\r3-make-win.exe
455471
set T=../../../src/tools

make/r3.manifest

+12
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,16 @@
1212
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
1313
</windowsSettings>
1414
</application>
15+
<dependency>
16+
<dependentAssembly>
17+
<assemblyIdentity
18+
type="win32"
19+
name="Microsoft.Windows.Common-Controls"
20+
version="6.0.0.0"
21+
processorArchitecture="*"
22+
publicKeyToken="6595b64144ccf1df"
23+
language="*"
24+
/>
25+
</dependentAssembly>
26+
</dependency>
1527
</assembly>

make/r3.rc

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,5 @@ BEGIN
2828
101 "Rebol 3 (Oldes branch)"
2929
END
3030

31-
2 MANIFEST "r3.manifest"
31+
1 MANIFEST "r3.manifest"
3232

src/boot/sysobj.r

+6
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,12 @@ view: context [
394394
scroll-page
395395

396396
drop-file
397+
398+
click
399+
change
400+
focus
401+
unfocus
402+
scroll
397403
]
398404
event-keys: [
399405
; Event types. Order dependent for C and REBOL.

src/boot/window.r

+14-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,20 @@ REBOL [
1919
]
2020

2121
words: [
22-
;gui-metric
22+
;- widgets
23+
button
24+
check
25+
radio
26+
field
27+
area
28+
text
29+
text-list
30+
progress
31+
slider
32+
date-time
33+
group-box
34+
35+
;- gui-metric
2336
border-fixed
2437
border-size
2538
screen-size

src/core/a-lib.c

+26-7
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,23 @@ RL_API void *RL_Make_Block(u32 size)
545545
return Make_Block(size);
546546
}
547547

548+
RL_API void RL_Expand_Series(REBSER *series, REBCNT index, REBCNT delta)
549+
/*
550+
** Expand a series at a particular index point by the number
551+
** number of units specified by delta.
552+
**
553+
** Returns:
554+
**
555+
** Arguments:
556+
** series - series to expand
557+
** index - position where to expand
558+
** delta - number of UNITS to expand from TAIL (keeping terminator)
559+
*/
560+
{
561+
Expand_Series(series, index, delta);
562+
}
563+
564+
548565
RL_API void *RL_Make_String(u32 size, int unicode)
549566
/*
550567
** Allocate a new string or binary series.
@@ -630,7 +647,7 @@ RL_API void RL_Protect_GC(REBSER *series, u32 flags)
630647
(flags == 1) ? SERIES_SET_FLAG(series, SER_KEEP) : SERIES_CLR_FLAG(series, SER_KEEP);
631648
}
632649

633-
RL_API int RL_Get_String(REBSER *series, u32 index, void **str)
650+
RL_API int RL_Get_String(REBSER *series, u32 index, void **str, REBOOL needs_wide)
634651
/*
635652
** Obtain a pointer into a string (bytes or unicode).
636653
**
@@ -641,6 +658,7 @@ RL_API int RL_Get_String(REBSER *series, u32 index, void **str)
641658
** series - string series pointer
642659
** index - index from beginning (zero-based)
643660
** str - pointer to first character
661+
** needs_wide - unicode string is required, converts if needed
644662
** Notes:
645663
** If the len is less than zero, then the string is optimized to
646664
** codepoints (chars) 255 or less for ASCII and LATIN-1 charsets.
@@ -651,13 +669,14 @@ RL_API int RL_Get_String(REBSER *series, u32 index, void **str)
651669
int len = (index >= series->tail) ? 0 : series->tail - index;
652670

653671
if (BYTE_SIZE(series)) {
654-
*str = BIN_SKIP(series, index);
655-
len = -len;
656-
}
657-
else {
658-
*str = UNI_SKIP(series, index);
672+
if (needs_wide) {
673+
Widen_String(series);
674+
} else {
675+
*str = BIN_SKIP(series, index);
676+
return -len;
677+
}
659678
}
660-
679+
*str = UNI_SKIP(series, index);
661680
return len;
662681
}
663682

src/core/t-gob.c

+78-16
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,9 @@ const REBCNT Gob_Flag_Words[] = {
324324
/*
325325
***********************************************************************/
326326
{
327+
REBVAL *spec;
328+
REBVAL *hndl;
329+
327330
switch (VAL_WORD_CANON(word)) {
328331
case SYM_OFFSET:
329332
return Set_Pair(&(gob->offset), val);
@@ -343,6 +346,30 @@ const REBCNT Gob_Flag_Words[] = {
343346
else if (IS_NONE(val)) SET_GOB_TYPE(gob, GOBT_NONE);
344347
else return FALSE;
345348
break;
349+
#ifdef HAS_WIDGET_GOB
350+
case SYM_WIDGET:
351+
//printf("WIDGET GOB\n");
352+
SET_GOB_TYPE(gob, GOBT_WIDGET);
353+
SET_GOB_OPAQUE(gob);
354+
355+
GOB_CONTENT(gob) = Make_Block(4); // [handle type spec data]
356+
hndl = Append_Value(GOB_CONTENT(gob));
357+
Append_Value(GOB_CONTENT(gob)); // used to cache type on host's side
358+
spec = Append_Value(GOB_CONTENT(gob));
359+
Append_Value(GOB_CONTENT(gob)); // used to cache result data
360+
361+
SET_HANDLE(hndl, 0, SYM_WIDGET, 0);
362+
363+
if (IS_WORD(val) || IS_LIT_WORD(val)) {
364+
Set_Block(spec, Make_Block(1));
365+
Append_Val(VAL_SERIES(spec), val);
366+
}
367+
else if (IS_BLOCK(val)) {
368+
Set_Block(spec, VAL_SERIES(val));
369+
}
370+
else return FALSE;
371+
break;
372+
#endif // HAS_WIDGET_GOB
346373

347374
case SYM_DRAW:
348375
CLR_GOB_OPAQUE(gob);
@@ -383,7 +410,7 @@ const REBCNT Gob_Flag_Words[] = {
383410
if (IS_TUPLE(val)) {
384411
SET_GOB_TYPE(gob, GOBT_COLOR);
385412
Set_Pixel_Tuple((REBYTE*)&GOB_CONTENT(gob), val);
386-
if (VAL_TUPLE_LEN(val) < 4 || VAL_TUPLE(val)[3] == 0)
413+
if (VAL_TUPLE_LEN(val) < 4 || VAL_TUPLE(val)[3] == 255)
387414
SET_GOB_OPAQUE(gob);
388415
}
389416
else if (IS_NONE(val)) SET_GOB_TYPE(gob, GOBT_NONE);
@@ -406,6 +433,11 @@ const REBCNT Gob_Flag_Words[] = {
406433
break;
407434

408435
case SYM_DATA:
436+
#ifdef HAS_WIDGET_GOB
437+
if (GOB_TYPE(gob) == GOBT_WIDGET) {
438+
OS_SET_WIDGET_DATA(gob, val);
439+
} else {
440+
#endif
409441
SET_GOB_DTYPE(gob, GOBD_NONE);
410442
if (IS_OBJECT(val)) {
411443
SET_GOB_DTYPE(gob, GOBD_OBJECT);
@@ -430,6 +462,9 @@ const REBCNT Gob_Flag_Words[] = {
430462
else if (IS_NONE(val))
431463
SET_GOB_TYPE(gob, GOBT_NONE);
432464
else return FALSE;
465+
#ifdef HAS_WIDGET_GOB
466+
}
467+
#endif
433468
break;
434469

435470
case SYM_FLAGS:
@@ -462,6 +497,7 @@ const REBCNT Gob_Flag_Words[] = {
462497
/*
463498
***********************************************************************/
464499
{
500+
REBSER *data;
465501
switch (VAL_WORD_CANON(word)) {
466502

467503
case SYM_OFFSET:
@@ -479,6 +515,14 @@ const REBCNT Gob_Flag_Words[] = {
479515
else goto is_none;
480516
break;
481517

518+
#ifdef HAS_WIDGET_GOB
519+
case SYM_WIDGET:
520+
data = VAL_SERIES(GOB_WIDGET_SPEC(gob));
521+
Init_Word(val, VAL_WORD_CANON(BLK_HEAD(data)));
522+
VAL_SET(val, REB_LIT_WORD);
523+
break;
524+
#endif
525+
482526
case SYM_DRAW:
483527
if (GOB_TYPE(gob) == GOBT_DRAW) {
484528
Set_Block(val, GOB_CONTENT(gob)); // Note: compiler optimizes SET_BLOCKs below
@@ -531,20 +575,27 @@ const REBCNT Gob_Flag_Words[] = {
531575
break;
532576

533577
case SYM_DATA:
578+
#ifdef HAS_WIDGET_GOB
579+
if (GOB_TYPE(gob) == GOBT_WIDGET) {
580+
return OS_GET_WIDGET_DATA(gob, val);
581+
}
582+
#endif
583+
data = GOB_DATA(gob);
584+
534585
if (GOB_DTYPE(gob) == GOBD_OBJECT) {
535-
SET_OBJECT(val, GOB_DATA(gob));
586+
SET_OBJECT(val, data);
536587
}
537588
else if (GOB_DTYPE(gob) == GOBD_BLOCK) {
538-
Set_Block(val, GOB_DATA(gob));
589+
Set_Block(val, data);
539590
}
540591
else if (GOB_DTYPE(gob) == GOBD_STRING) {
541-
Set_String(val, GOB_DATA(gob));
592+
Set_String(val, data);
542593
}
543594
else if (GOB_DTYPE(gob) == GOBD_BINARY) {
544-
SET_BINARY(val, GOB_DATA(gob));
595+
SET_BINARY(val, data);
545596
}
546597
else if (GOB_DTYPE(gob) == GOBD_INTEGER) {
547-
SET_INTEGER(val, (REBIPT)GOB_DATA(gob));
598+
SET_INTEGER(val, (REBIPT)data);
548599
}
549600
else goto is_none;
550601
break;
@@ -591,23 +642,29 @@ const REBCNT Gob_Flag_Words[] = {
591642
{
592643
REBSER *ser = Make_Block(10);
593644
REBVAL *val;
594-
REBINT words[6] = {SYM_OFFSET, SYM_SIZE, SYM_ALPHA, 0};
595-
REBVAL *vals[6];
596-
REBINT n = 0;
597645
REBVAL *val1;
598646
REBCNT sym;
599647

600-
for (n = 0; words[n]; n++) {
648+
val = Append_Value(ser);
649+
Init_Word(val, SYM_OFFSET);
650+
VAL_SET(val, REB_SET_WORD);
651+
val = Append_Value(ser);
652+
SET_PAIR(val, GOB_X(gob), GOB_Y(gob));
653+
654+
val = Append_Value(ser);
655+
Init_Word(val, SYM_SIZE);
656+
VAL_SET(val, REB_SET_WORD);
657+
val = Append_Value(ser);
658+
SET_PAIR(val, GOB_W(gob), GOB_H(gob));
659+
660+
if (!GET_GOB_FLAG(gob, GOBF_OPAQUE) && GOB_ALPHA(gob) < 255) {
601661
val = Append_Value(ser);
602-
Init_Word(val, words[n]);
662+
Init_Word(val, SYM_ALPHA);
603663
VAL_SET(val, REB_SET_WORD);
604-
vals[n] = Append_Value(ser);
664+
val = Append_Value(ser);
665+
SET_INTEGER(val, 255 - GOB_ALPHA(gob));
605666
}
606667

607-
SET_PAIR(vals[0], GOB_X(gob), GOB_Y(gob));
608-
SET_PAIR(vals[1], GOB_W(gob), GOB_H(gob));
609-
SET_INTEGER(vals[2], GOB_ALPHA(gob));
610-
611668
if (!GOB_TYPE(gob)) return ser;
612669

613670
if (GOB_CONTENT(gob)) {
@@ -620,6 +677,11 @@ const REBCNT Gob_Flag_Words[] = {
620677
case GOBT_IMAGE:
621678
sym = SYM_IMAGE;
622679
break;
680+
#ifdef HAS_WIDGET_GOB
681+
case GOBT_WIDGET:
682+
sym = SYM_WIDGET;
683+
break;
684+
#endif
623685
case GOBT_STRING:
624686
case GOBT_TEXT:
625687
sym = SYM_TEXT;

src/include/reb-config.h

+1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ These are now obsolete (as of A107) and should be removed:
101101
#define OS_CRLF TRUE // uses CRLF as line terminator
102102
#define OS_DIR_SEP '\\' // file path separator (Thanks Bill.)
103103
#define HAS_ASYNC_DNS // supports it
104+
#define HAS_WIDGET_GOB // supports it
104105
#define ATOI // supports it
105106
#define ATOI64 // supports it
106107
#define ITOA64 // supports it

src/include/reb-gob.h

+6
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ enum GOB_TYPES { // Types of content
6868
GOBT_NONE = 0,
6969
GOBT_COLOR,
7070
GOBT_IMAGE,
71+
GOBT_WIDGET, // must be between IMAGE and STRING so GC can mark its content!
7172
GOBT_STRING,
7273
GOBT_DRAW,
7374
GOBT_TEXT,
@@ -178,6 +179,11 @@ typedef struct gob_window { // Maps gob to window
178179
#define GOB_PARENT(g) ((g)->parent)
179180
#define GOB_CONTENT(g) ((g)->content)
180181

182+
#define GOB_WIDGET_HANDLE(g) (BLK_HEAD(GOB_CONTENT(g)))
183+
#define GOB_WIDGET_TYPE(g) (BLK_SKIP(GOB_CONTENT(g), 1))
184+
#define GOB_WIDGET_SPEC(g) (BLK_SKIP(GOB_CONTENT(g), 2))
185+
#define GOB_WIDGET_DATA(g) (BLK_SKIP(GOB_CONTENT(g), 3))
186+
181187
// Control dependencies on series structures:
182188
#ifdef REB_DEF
183189
#define GOB_STRING(g) SERIES_DATA(GOB_CONTENT(g))

src/include/sys-value.h

+1
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,7 @@ typedef struct Reb_Series_Ref
536536
#define VAL_SERIES(v) ((v)->data.series.series)
537537
#define VAL_INDEX(v) ((v)->data.series.index)
538538
#define VAL_TAIL(v) (VAL_SERIES(v)->tail)
539+
#define VAL_REST(v) (VAL_SERIES(v)->rest)
539540
#define VAL_LEN(v) (Val_Series_Len(v))
540541

541542
#define VAL_DATA(s) (VAL_BIN_HEAD(s) + (VAL_INDEX(s) * VAL_SERIES_WIDTH(s)))

src/os/host-ext-test.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ RXIEXT int RX_Call(int cmd, RXIFRM *frm, void *ctx) {
201201
break;
202202

203203
case 4: //command [{return word from string} str [string!]]
204-
RL_GET_STRING(RXA_SERIES(frm, 1), 0, (void*)(&str)); // latin-1 only for test
204+
RL_GET_STRING(RXA_SERIES(frm, 1), 0, (void*)(&str), FALSE); // latin-1 only for test
205205
RXA_WORD(frm, 1) = RL_MAP_WORD(str);
206206
RXA_TYPE(frm, 1) = RXT_WORD;
207207
break;

src/os/host-main.c

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ REBARGS Main_Args;
6969
#ifdef TO_WINDOWS
7070
#define MAX_TITLE_LENGTH 1024
7171
HINSTANCE App_Instance = 0;
72+
HWND Focused_Window = 0;
7273
WCHAR App_Title[MAX_TITLE_LENGTH]; //will be filled later from the resources file
7374
#endif
7475

0 commit comments

Comments
 (0)