Giter Club home page Giter Club logo

notes's People

Contributors

qtxie avatar

Watchers

 avatar  avatar

notes's Issues

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.

  1. Simply fork red/red into a new repo red/view. ;-)
  2. All the changes/issues related to red/core happens in red/red.
  3. All the changes/issues related to red/view happens in red/view.
  4. Merge or cherry-pick commits between those two repos regularly or when needed.

This gives us the following benefits.

  1. Make it easier to have two teams to work on red/core and red/view.
  2. Sperate issues.
  3. Easy to handle, simple work flow.

GOB-based Face! (Draft)

Example of GOB-based widget

gob2020-3-302

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.

image

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:
image

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
    ]
]

image

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
    ]
]

[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 the scrollable flag in the flags facet to enable it.
view [b: base 300x300 do [b/flags: [scrollable]]]

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

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.