notes's Issues
GOB-based Face! (Draft)
Example of GOB-based widget
Red [
Needs: View
Config: [GUI-engine: 'custom]
]
;; styles
btn-radius: 4
btn-shadow-normal: [
0x3 1 -2 0.0.0.204
0x2 2 0.0.0.220
0x1 5 0.0.0.224
]
btn-shadow-down: [
0x3 7 -2 0.0.0.180
0x2 8 0.0.0.200
0x1 11 0.0.0.204
]
btn-normal: make gob-style! [
background: 255.255.255
border-radius: btn-radius
shadow: btn-shadow-normal
]
btn-hover: make gob-style! [
background: 240.240.240
border-radius: btn-radius
shadow: btn-shadow-normal
]
btn-down: make gob-style! [
background: 210.210.210
border-radius: btn-radius
shadow: btn-shadow-down
]
;; widgets
register-widget 'button make gob! [
actors: reduce [
'over func [gob event][
gob/styles: either find event/flags 'away [btn-normal][btn-hover]
]
'down func [gob evt][
gob/styles: btn-down
]
'up func [gob evt][
gob/styles: btn-normal
]
]
styles: btn-normal
]
register-widget 'base make gob! []
view [
backdrop 102.204.255
button 80x30 "Click Me" [probe "Hello Red"]
base 100x100 all-over on-over [probe event/offset]
]
Extend Face! Object
The face! object is extended to have a gob
facet, which does the actual job.
face!: object [
type: 'face
offset: none
size: none
text: none
image: none
color: none
menu: none
data: none
enabled?: yes
visible?: yes
selected: none
flags: none
options: none
parent: none
pane: none
state: none
rate: none
edge: none
para: none
font: none
actors: none
extra: none
draw: none
gob: none ;@@
]
Event flow
All the events (mouse events, keyboard events, etc.) are passed to the face first, then to the gob. The face event handler could return stop
to prevent the event from passing to the gob.
Graphic Object (GOB)
A GOB is very lightweight (96 bytes now) compare to face. Complex UI components can be built by composing many gobs.
List of available fields of gob:
Field | Datatype | Description |
---|---|---|
offset | pair! | the x-y coordinate relative to parent |
size | pair | width and height of gob (note below) |
pane | block! | a block of child gobs |
parent | gob! | the parent gob |
data | any-type! | normally used to reference data related to the gob |
face | face! | the face object the gob linked with |
draw | block! | a block of draw commands |
color | tuple! | background color of the gob in R.G.B or R.G.B.A format |
text | string! | text displayed in the gob |
image | image! | image displayed in the face background |
enabled? | logic! | enable or disable events on the gob |
visible? | logic! | display or hide the gob |
flags | block! | ?? Do we need it? |
actors | block! | User-provided events handlers |
styles | object! | gob-style! object, styling the gob |
... | ... | ... |
Note: The gob uses a box model. Every box is composed of three parts (or areas), defined by their respective edges: the content edge, padding edge and border edge.
If you set an gob's width to 100 pixels, that 100 pixels will include any border or padding you added, and the content box will shrink to absorb that extra width.
The draw commands in gob/draw
will be draw in the content box.
Gob style
Gob-style objects are clones of gob-style! template object.
gob-style!: object [
state: none ;-- Internal state info
on-change*: function [word old new][
;-- update field
]
on-deep-change*: function [owner word target action new index part][
;-- update field
]
]
When link a gob-style! object to a gob, the following fields will be processed by the gob. Other fields will be ignored.
TBD
background:
background-clip:
background-size:
background-color:
background-image:
background-repeat:
background-origin:
background-position:
background-attachment:
background-blend-mode:
border:
border-style:
border-width:
border-color:
border-image:
border-radius:
border-bottom:
border-bottom-color:
border-bottom-style:
border-bottom-width:
border-bottom-radius:
border-top:
border-top-color:
border-top-style:
border-top-width:
border-top-radius:
border-left:
border-left-color:
border-left-style:
border-left-width:
border-right:
border-right-color:
border-right-style:
border-right-width:
padding:
padding-left:
padding-top:
padding-right:
padding-bottom:
font:
font-family:
font-size:
font-style:
font-weight:
tab-size:
text-align:
text-indent:
text-overflow:
text-shadow:
text-transform:
text-decoration:
text-decoration-color:
text-decoration-line:
text-decoration-style:
letter-spacing:
line-height:
transform:
transform-origin:
transform-style:
transition:
transition-delay:
transition-duration:
transition-property:
transition-timing-function:
opacity:
shadow:
caret-color:
text-color:
cursor:
direction:
white-space:
word-break:
word-spacing:
word-wrap:
writing-mode:
blend-mode:
outline:
;-- filter
drop-shadow:
blur:
grayscale:
hue-rotate:
brightness:
contrast:
saturate:
sepia:
solid:
DRAW shadow
shadow off|<offset> <blur> <spread> <color> inset
- off: Turn off the shadow effect.
- offset (pair! required): The offset of the shadow.
- blur (integer! optional): The blur radius. The higher the number, the more blurred the shadow will be.
- spread (integer! optional): The spread radius. A positive value increases the size of the shadow, a negative value decreases the size of the shadow.
- color (tuple! optional): The color of the shadow. The default value is the text color.
- inset (optional): Changes the shadow from an outer shadow (outset) to an inner shadow.
The shadow
command define a shadow effect (or several) which apply to the following draw commands. For examples:
view [
base 300x300 white draw [
fill-pen white
shadow 5x10 18 255.0.0
box 50x50 150x150
]
]
This will draw a box with red shadow:
You can also apply multiple shadow effects.
view [
base 300x300 white draw [
fill-pen white
shadow 5x10 18 255.0.0
shadow -5x-10 18 0.0.255
box 50x50 150x150
]
]
The shadow effect will apply to all the shapes until it's turned off.
view [
base 300x300 white draw [
fill-pen white
shadow 5x10 18 255.0.0
shadow -5x-10 18 0.0.255
box 30x30 130x130 ;-- has shadow
circle 200x200 50 ;-- has shadow
shadow off
box 200x30 280x110 ;-- no shadow
]
]
GET Word and Path in DRAW
Should we support GET word and path in DRAW:
y: 0x120 view layout [box 600x300 effect [draw [pen yellow line y 500x150]]]
colors: reduce [red green blue]
view layout [box effect [draw [pen colors/2 box]]]
Low-level Audio in R/S
API详细说明参考:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1386r2.pdf
目前我们只支持 Sample Type float32! 就行。三大平台应该都支持这个格式。
各平台使用的框架:
- Windows (via WASAPI)
- macOS (via CoreAudio)
- Linux (via ALSA)
计划支持的功能:
- Enumerate all available audio devices.
- Get the current default input and output devices.
- Enumerate known supported input and output stream formats for a device.
- Get the current default input and output stream formats for a device.
- Build and run input and output PCM streams on a chosen device with a given stream format
;-- implementation-defined type
#case [
OS = 'Windows [
#define audio-buffer-size! xxx
#define audio-sample-rate! xxx
#define audio-device-id! xxx
audio-clock!: alias struct! [xxx]
]
OS = ...
]
#define MAX_NUM_CHANNELS 16
#enum audio-sample-type! [
SAMPLE_TYPE_F32
SAMPLE_TYPE_I16
]
#enum audio-device-event! [
DEVICE_CHANGED
DEFAULT_INPUT_CHANGED
DEFAULT_OUTPUT_CHANGED
]
audio-buffer!: alias struct! [
contiguous? [logic!]
frames-count [integer!]
channels-count [integer!]
sample-type [audio-sample-type!]
stride [integer!]
channels [ptr-ptr!]
]
audio-device-io!: alias struct! [
input-buffer [audio-buffer!]
input-time [audio-clock!]
output-buffer [audio-buffer!]
output-time [audio-clock!]
]
audio-io-callback!: alias function! [
dev [audio-device!]
io [audio-device-io!]
]
audio-device-callback!: alias function! [
dev [audio-device!]
]
audio-changed-callback!: alias function! []
audio-device!: alias struct! [
;-- implementation-defined
;-- 每个实现自己定里面需要的字段
]
audio: context [
all-devices: func [
count [int-ptr!] ;-- number of devices
return: [audio-device!] ;-- an array of audio-device!
]
input-devices: func [
count [int-ptr!] ;-- number of input devices
return: [audio-device!] ;-- an array of audio-device!
]
output-devices: func [
count [int-ptr!] ;-- number of output devices
return: [audio-device!] ;-- an array of audio-device!
]
default-input-device: func [
return: [audio-device!]
]
default-output-device: func [
return: [audio-device!]
]
set-device-changed-callback: func [
event [audio-device-event!]
cb [int-ptr!] ;-- audio-changed-callback!
]
free-device: func [
dev [audio-device!]
]
free-devices: func [
devs [audio-device!] ;-- an array of audio-device!
count [integer!] ;-- number of devices
/local
p [byte-ptr!]
][
p: as byte-ptr! devs
loop count [
free-device devs
devs: devs + 1
]
free p
]
]
audio-device: context [
name: func [
dev [audio-device!]
return: [c-string!]
]
id: func [
dev [audio-device!]
return: [audio-device-id!]
]
input-channels-count: func [
dev [audio-device!]
return: [integer!]
]
output-channels-count: func [
dev [audio-device!]
return: [integer!]
]
buffer-size: func [
dev [audio-device!]
return: [audio-buffer-size!]
]
set-buffer-size: func [
dev [audio-device!]
size [audio-buffer-size!]
return: [logic!]
]
sample-rate: func [
dev [audio-device!]
return: [audio-sample-rate!]
]
set-sample-rate: func [
dev [audio-device!]
rate [audio-sample-rate!]
return: [logic!]
]
input?: func [
dev [audio-device!]
return: [logic!]
]
output?: func [
dev [audio-device!]
return: [logic!]
]
running?: func [
dev [audio-device!]
return: [logic!]
]
sample-type-support?: func [
dev [audio-device!]
return: [logic!]
]
can-connect?: func [
dev [audio-device!]
return: [logic!]
]
can-process?: func [
dev [audio-device!]
return: [logic!]
]
has-unprocessed-io?: func [
dev [audio-device!]
return: [logic!]
]
process: func [
dev [audio-device!]
type [audio-sample-rate!]
io-cb [int-ptr!] ;-- audio-io-callback!
]
connect: func [
dev [audio-device!]
type [audio-sample-rate!]
io-cb [int-ptr!] ;-- audio-io-callback!
]
start: func [
dev [audio-device!]
start-cb [int-ptr!] ;-- audio-device-callback!
stop-cb [int-ptr!] ;-- audio-device-callback!
]
stop: func [
dev [audio-device!]
return: [logic!]
]
wait: func [
dev [audio-device!]
]
]
audio-buffer: context [
frames-count: func [
buf [audio-buffer!]
return: [ulong!]
]
channels-count: func [
buf [audio-buffer!]
return: [ulong!]
]
samples-count: func [
buf [audio-buffer!]
return: [ulong!]
]
contiguous?: func [
buf [audio-buffer!]
return: [logic!]
]
channels-contiguous?: func [
buf [audio-buffer!]
return: [logic!]
]
frames-contiguous?: func [
buf [audio-buffer!]
return: [logic!]
]
data: func [
buf [audio-buffer!]
return: [float32-ptr!]
]
write: func [
buf [audio-buffer!]
frame-idx [integer!]
channel-idx [integer!]
value [float32!]
]
read: func [
buf [audio-buffer!]
frame-idx [integer!]
channel-idx [integer!]
return: [float32!]
]
;@@ implements those functions onces we have int16! in R/S
;data-i16: func [
; buf [audio-buffer!]
; return: [int16!]
;]
;write-i16: func [
; buf [audio-buffer!]
; frame-idx [integer!]
; channel-idx [integer!]
; value [int16!]
;]
;read-i16: func [
; buf [audio-buffer!]
; frame-idx [integer!]
; channel-idx [integer!]
; return: [int16!]
;]
]
示例代码:
Ports from: https://github.com/stdcpp-audio/libstdaudio/blob/master/examples/level_meter.cpp
#define COND_CC [#if OS <> 'Windows [[cdecl]]]
audio-io-cb: func [
COND_CC
dev [audio-device!]
io [audio-device-io!]
][
...
]
test: func [return: [integer!]][
device: audio/default-input-device
if null? device [return 1]
audio-device/connect device SAMPLE_TYPE_F32 as int-ptr! :audio-io-cb
audio-device/start device null null
while [audio-device/running? device][
;sleep 250ms
]
]
后续需要在这个库的基础上实现Sound API。因此在实现的过程中,在查阅系统API的文档时,可以对相关的系统API留个心眼。
Sound API大致如下:
Load-WAV
Load-MP3
Play-Sound
Stop-Sound
Pause-Sound
Loop-Sound
Set-Volume
Set-Pan
Set-Delay
[Draft] ScrollViewer and Scroller
There are two elements that enable scrolling in Red/View: ScrollView
and Scroller
.
ScrollView
The ScrollView is a content container, it has a horizontal Scroller and a vertical Scroller. It implements the interaction details for a scrollable face. The user just need to populate it with sub faces. The scrollers will automatically show or hide according to the size of the bounding box of the sub faces in the ScrollView.
For example, builds a ListView by using ScrollView.
item!: make face! [type: 'base size: 200x50]
offset: 0x0
view [
sv: scrollview 202x600
button "Add Item" [
item: copy item!
item/offset: offset
append sv/pane item
offset/y: offset/y + item/size/y
]
]
Scroller
There are two types of scroller: Standalone Scroller
and Embeded Scroller
.
- Standalone Scroller
TBD: should we use face! or a special scroller! object?
scroller!: object [
position: none ;-- knob position
page-size: none ;-- page size
min-size: 1 ;-- minimum value
max-size: none ;-- maximum value
visible?: yes
vertical?: yes ;-- read only. YES: vertical NO: horizontal
parent: none
]
- Embeded Scroller
The embeded scrollers use the same object definition as the standalone scroller, but them attach to the base face, the position of them are fixed. It's easier to use than the standalone scroller, you don't need to handle the size and position of the scroller when resizing the parent base face.
Use thescrollable
flag in theflags
facet to enable it.
view [b: base 300x300 do [b/flags: [scrollable]]]
Separate Red/Core and Red/View into two repos
Now Red/Core and Red/View are in the same repository (red/red). Each of them is a big project, they should be in different repository.
We attampted to split view
into a standalone repo by making it a git module before. It did not work well. The view module integrates with the runtime so tightly. They are interdependent. While a git module works well only if it's one-way dependency.
Here I propose a new way to sperate it.
- Simply fork
red/red
into a new repored/view
. ;-) - All the changes/issues related to red/core happens in red/red.
- All the changes/issues related to red/view happens in red/view.
- Merge or cherry-pick commits between those two repos regularly or when needed.
This gives us the following benefits.
- Make it easier to have two teams to work on red/core and red/view.
- Sperate issues.
- Easy to handle, simple work flow.
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.