Skip to content

Commit

Permalink
FEAT: introducing _native GOB widgets_ for Windows OS.
Browse files Browse the repository at this point in the history
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
```
  • Loading branch information
Oldes committed Mar 7, 2019
1 parent 3f182e9 commit 68d210a
Show file tree
Hide file tree
Showing 19 changed files with 679 additions and 86 deletions.
22 changes: 19 additions & 3 deletions make/msvc/Make-vs-project.r3
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ VS: context [

SourcePath: ""

AdditionalDependencies: "wsock32.lib;comdlg32.lib;"
AdditionalDependencies: rejoin [
"wsock32.lib;comdlg32.lib;"
"winmm.lib;" ;- for MIDI
"Gdi32.lib;Comctl32.lib;UxTheme.lib;" ;- for View
]

Sources: []

Expand Down Expand Up @@ -448,8 +452,20 @@ vs/Sources: compose/only [
]
vs/IncludePath-x86:
vs/IncludePath-x64: "..\..\..\src\include;"
vs/PreprocessorDefinitions-x86: {TO_WIN32;REB_CORE;REB_EXE;ENDIAN_LITTLE;_FILE_OFFSET_BITS=64;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;USE_LZMA;}
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;}

common-definitions: {REB_EXE;ENDIAN_LITTLE;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;_FILE_OFFSET_BITS=64;}
optional-components: {USE_MIDI_DEVICE;USE_PNG_CODEC;USE_JPG_CODEC;USE_LZMA;} ;TEST_EXTENSIONS;
vs/PreprocessorDefinitions-x86: rejoin [
common-definitions
{TO_WIN32;}
optional-components
]
vs/PreprocessorDefinitions-x64: rejoin [
common-definitions
{TO_WIN32_X64;__LLP64__;}
optional-components
]

vs/Prebuild-x86: {
set REBOL=..\..\prebuild\r3-make-win.exe
set T=../../../src/tools
Expand Down
12 changes: 12 additions & 0 deletions make/r3.manifest
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,16 @@
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
</windowsSettings>
</application>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</assembly>
2 changes: 1 addition & 1 deletion make/r3.rc
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ BEGIN
101 "Rebol 3 (Oldes branch)"
END

2 MANIFEST "r3.manifest"
1 MANIFEST "r3.manifest"

6 changes: 6 additions & 0 deletions src/boot/sysobj.r
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,12 @@ view: context [
scroll-page

drop-file

click
change
focus
unfocus
scroll
]
event-keys: [
; Event types. Order dependent for C and REBOL.
Expand Down
15 changes: 14 additions & 1 deletion src/boot/window.r
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,20 @@ REBOL [
]

words: [
;gui-metric
;- widgets
button
check
radio
field
area
text
text-list
progress
slider
date-time
group-box

;- gui-metric
border-fixed
border-size
screen-size
Expand Down
33 changes: 26 additions & 7 deletions src/core/a-lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,23 @@ RL_API void *RL_Make_Block(u32 size)
return Make_Block(size);
}

RL_API void RL_Expand_Series(REBSER *series, REBCNT index, REBCNT delta)
/*
** Expand a series at a particular index point by the number
** number of units specified by delta.
**
** Returns:
**
** Arguments:
** series - series to expand
** index - position where to expand
** delta - number of UNITS to expand from TAIL (keeping terminator)
*/
{
Expand_Series(series, index, delta);
}


RL_API void *RL_Make_String(u32 size, int unicode)
/*
** Allocate a new string or binary series.
Expand Down Expand Up @@ -630,7 +647,7 @@ RL_API void RL_Protect_GC(REBSER *series, u32 flags)
(flags == 1) ? SERIES_SET_FLAG(series, SER_KEEP) : SERIES_CLR_FLAG(series, SER_KEEP);
}

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

if (BYTE_SIZE(series)) {
*str = BIN_SKIP(series, index);
len = -len;
}
else {
*str = UNI_SKIP(series, index);
if (needs_wide) {
Widen_String(series);
} else {
*str = BIN_SKIP(series, index);
return -len;
}
}

*str = UNI_SKIP(series, index);
return len;
}

Expand Down
94 changes: 78 additions & 16 deletions src/core/t-gob.c
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,9 @@ const REBCNT Gob_Flag_Words[] = {
/*
***********************************************************************/
{
REBVAL *spec;
REBVAL *hndl;

switch (VAL_WORD_CANON(word)) {
case SYM_OFFSET:
return Set_Pair(&(gob->offset), val);
Expand All @@ -343,6 +346,30 @@ const REBCNT Gob_Flag_Words[] = {
else if (IS_NONE(val)) SET_GOB_TYPE(gob, GOBT_NONE);
else return FALSE;
break;
#ifdef HAS_WIDGET_GOB
case SYM_WIDGET:
//printf("WIDGET GOB\n");
SET_GOB_TYPE(gob, GOBT_WIDGET);
SET_GOB_OPAQUE(gob);

GOB_CONTENT(gob) = Make_Block(4); // [handle type spec data]
hndl = Append_Value(GOB_CONTENT(gob));
Append_Value(GOB_CONTENT(gob)); // used to cache type on host's side
spec = Append_Value(GOB_CONTENT(gob));
Append_Value(GOB_CONTENT(gob)); // used to cache result data

SET_HANDLE(hndl, 0, SYM_WIDGET, 0);

if (IS_WORD(val) || IS_LIT_WORD(val)) {
Set_Block(spec, Make_Block(1));
Append_Val(VAL_SERIES(spec), val);
}
else if (IS_BLOCK(val)) {
Set_Block(spec, VAL_SERIES(val));
}
else return FALSE;
break;
#endif // HAS_WIDGET_GOB

case SYM_DRAW:
CLR_GOB_OPAQUE(gob);
Expand Down Expand Up @@ -383,7 +410,7 @@ const REBCNT Gob_Flag_Words[] = {
if (IS_TUPLE(val)) {
SET_GOB_TYPE(gob, GOBT_COLOR);
Set_Pixel_Tuple((REBYTE*)&GOB_CONTENT(gob), val);
if (VAL_TUPLE_LEN(val) < 4 || VAL_TUPLE(val)[3] == 0)
if (VAL_TUPLE_LEN(val) < 4 || VAL_TUPLE(val)[3] == 255)
SET_GOB_OPAQUE(gob);
}
else if (IS_NONE(val)) SET_GOB_TYPE(gob, GOBT_NONE);
Expand All @@ -406,6 +433,11 @@ const REBCNT Gob_Flag_Words[] = {
break;

case SYM_DATA:
#ifdef HAS_WIDGET_GOB
if (GOB_TYPE(gob) == GOBT_WIDGET) {
OS_SET_WIDGET_DATA(gob, val);
} else {
#endif
SET_GOB_DTYPE(gob, GOBD_NONE);
if (IS_OBJECT(val)) {
SET_GOB_DTYPE(gob, GOBD_OBJECT);
Expand All @@ -430,6 +462,9 @@ const REBCNT Gob_Flag_Words[] = {
else if (IS_NONE(val))
SET_GOB_TYPE(gob, GOBT_NONE);
else return FALSE;
#ifdef HAS_WIDGET_GOB
}
#endif
break;

case SYM_FLAGS:
Expand Down Expand Up @@ -462,6 +497,7 @@ const REBCNT Gob_Flag_Words[] = {
/*
***********************************************************************/
{
REBSER *data;
switch (VAL_WORD_CANON(word)) {

case SYM_OFFSET:
Expand All @@ -479,6 +515,14 @@ const REBCNT Gob_Flag_Words[] = {
else goto is_none;
break;

#ifdef HAS_WIDGET_GOB
case SYM_WIDGET:
data = VAL_SERIES(GOB_WIDGET_SPEC(gob));
Init_Word(val, VAL_WORD_CANON(BLK_HEAD(data)));
VAL_SET(val, REB_LIT_WORD);
break;
#endif

case SYM_DRAW:
if (GOB_TYPE(gob) == GOBT_DRAW) {
Set_Block(val, GOB_CONTENT(gob)); // Note: compiler optimizes SET_BLOCKs below
Expand Down Expand Up @@ -531,20 +575,27 @@ const REBCNT Gob_Flag_Words[] = {
break;

case SYM_DATA:
#ifdef HAS_WIDGET_GOB
if (GOB_TYPE(gob) == GOBT_WIDGET) {
return OS_GET_WIDGET_DATA(gob, val);
}
#endif
data = GOB_DATA(gob);

if (GOB_DTYPE(gob) == GOBD_OBJECT) {
SET_OBJECT(val, GOB_DATA(gob));
SET_OBJECT(val, data);
}
else if (GOB_DTYPE(gob) == GOBD_BLOCK) {
Set_Block(val, GOB_DATA(gob));
Set_Block(val, data);
}
else if (GOB_DTYPE(gob) == GOBD_STRING) {
Set_String(val, GOB_DATA(gob));
Set_String(val, data);
}
else if (GOB_DTYPE(gob) == GOBD_BINARY) {
SET_BINARY(val, GOB_DATA(gob));
SET_BINARY(val, data);
}
else if (GOB_DTYPE(gob) == GOBD_INTEGER) {
SET_INTEGER(val, (REBIPT)GOB_DATA(gob));
SET_INTEGER(val, (REBIPT)data);
}
else goto is_none;
break;
Expand Down Expand Up @@ -591,23 +642,29 @@ const REBCNT Gob_Flag_Words[] = {
{
REBSER *ser = Make_Block(10);
REBVAL *val;
REBINT words[6] = {SYM_OFFSET, SYM_SIZE, SYM_ALPHA, 0};
REBVAL *vals[6];
REBINT n = 0;
REBVAL *val1;
REBCNT sym;

for (n = 0; words[n]; n++) {
val = Append_Value(ser);
Init_Word(val, SYM_OFFSET);
VAL_SET(val, REB_SET_WORD);
val = Append_Value(ser);
SET_PAIR(val, GOB_X(gob), GOB_Y(gob));

val = Append_Value(ser);
Init_Word(val, SYM_SIZE);
VAL_SET(val, REB_SET_WORD);
val = Append_Value(ser);
SET_PAIR(val, GOB_W(gob), GOB_H(gob));

if (!GET_GOB_FLAG(gob, GOBF_OPAQUE) && GOB_ALPHA(gob) < 255) {
val = Append_Value(ser);
Init_Word(val, words[n]);
Init_Word(val, SYM_ALPHA);
VAL_SET(val, REB_SET_WORD);
vals[n] = Append_Value(ser);
val = Append_Value(ser);
SET_INTEGER(val, 255 - GOB_ALPHA(gob));
}

SET_PAIR(vals[0], GOB_X(gob), GOB_Y(gob));
SET_PAIR(vals[1], GOB_W(gob), GOB_H(gob));
SET_INTEGER(vals[2], GOB_ALPHA(gob));

if (!GOB_TYPE(gob)) return ser;

if (GOB_CONTENT(gob)) {
Expand All @@ -620,6 +677,11 @@ const REBCNT Gob_Flag_Words[] = {
case GOBT_IMAGE:
sym = SYM_IMAGE;
break;
#ifdef HAS_WIDGET_GOB
case GOBT_WIDGET:
sym = SYM_WIDGET;
break;
#endif
case GOBT_STRING:
case GOBT_TEXT:
sym = SYM_TEXT;
Expand Down
1 change: 1 addition & 0 deletions src/include/reb-config.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ These are now obsolete (as of A107) and should be removed:
#define OS_CRLF TRUE // uses CRLF as line terminator
#define OS_DIR_SEP '\\' // file path separator (Thanks Bill.)
#define HAS_ASYNC_DNS // supports it
#define HAS_WIDGET_GOB // supports it
#define ATOI // supports it
#define ATOI64 // supports it
#define ITOA64 // supports it
Expand Down
6 changes: 6 additions & 0 deletions src/include/reb-gob.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ enum GOB_TYPES { // Types of content
GOBT_NONE = 0,
GOBT_COLOR,
GOBT_IMAGE,
GOBT_WIDGET, // must be between IMAGE and STRING so GC can mark its content!
GOBT_STRING,
GOBT_DRAW,
GOBT_TEXT,
Expand Down Expand Up @@ -178,6 +179,11 @@ typedef struct gob_window { // Maps gob to window
#define GOB_PARENT(g) ((g)->parent)
#define GOB_CONTENT(g) ((g)->content)

#define GOB_WIDGET_HANDLE(g) (BLK_HEAD(GOB_CONTENT(g)))
#define GOB_WIDGET_TYPE(g) (BLK_SKIP(GOB_CONTENT(g), 1))
#define GOB_WIDGET_SPEC(g) (BLK_SKIP(GOB_CONTENT(g), 2))
#define GOB_WIDGET_DATA(g) (BLK_SKIP(GOB_CONTENT(g), 3))

// Control dependencies on series structures:
#ifdef REB_DEF
#define GOB_STRING(g) SERIES_DATA(GOB_CONTENT(g))
Expand Down
1 change: 1 addition & 0 deletions src/include/sys-value.h
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,7 @@ typedef struct Reb_Series_Ref
#define VAL_SERIES(v) ((v)->data.series.series)
#define VAL_INDEX(v) ((v)->data.series.index)
#define VAL_TAIL(v) (VAL_SERIES(v)->tail)
#define VAL_REST(v) (VAL_SERIES(v)->rest)
#define VAL_LEN(v) (Val_Series_Len(v))

#define VAL_DATA(s) (VAL_BIN_HEAD(s) + (VAL_INDEX(s) * VAL_SERIES_WIDTH(s)))
Expand Down
2 changes: 1 addition & 1 deletion src/os/host-ext-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ RXIEXT int RX_Call(int cmd, RXIFRM *frm, void *ctx) {
break;

case 4: //command [{return word from string} str [string!]]
RL_GET_STRING(RXA_SERIES(frm, 1), 0, (void*)(&str)); // latin-1 only for test
RL_GET_STRING(RXA_SERIES(frm, 1), 0, (void*)(&str), FALSE); // latin-1 only for test
RXA_WORD(frm, 1) = RL_MAP_WORD(str);
RXA_TYPE(frm, 1) = RXT_WORD;
break;
Expand Down
1 change: 1 addition & 0 deletions src/os/host-main.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ REBARGS Main_Args;
#ifdef TO_WINDOWS
#define MAX_TITLE_LENGTH 1024
HINSTANCE App_Instance = 0;
HWND Focused_Window = 0;
WCHAR App_Title[MAX_TITLE_LENGTH]; //will be filled later from the resources file
#endif

Expand Down
Loading

0 comments on commit 68d210a

Please sign in to comment.