Skip to content

Source Code Of The View System Functions

Christopher Ross-Gill edited this page Aug 1, 2016 · 1 revision
Rebol [
	Title: "Rebol View System Functions"
	Rights: "Copyright Rebol Technologies 2001-2007"
]

; The View system handles windowing, events, popups, requestors, and modal
; operations.  Normally VID provides the contents for these, but users are
; also allowed to build and display their own windows directly.

system/standard/font: context [
	name: "arial"
	style: none
	size: 12
	color: 0.0.0
	offset: 2x2
	space: 0x0
	shadow: none
]

system/standard/para: context [
	origin: 2x2
	margin: 2x2
	indent: 0x0
	tabs: 40
	wrap?: true
	scroll: 0x0
	align: 'left
	valign: 'top
]

view: func [
	"Displays a window view."
	window [gob! block! object!] "Window gob, VID face, or VID layout block"
	/options opts [block!] "Window options spec block"
	/local screen tmp xy
][
	if not screen: system/view/screen-gob [return none]

	; Convert option block to a map:
	opts: make map! reduce/no-set opts ; NONE is ok here

	; GOB based view:
	if gob? window [
		; Build the window:
		unless opts/as-is [
			tmp: window
			tmp/offset: 0x0
			window: make gob! [size: tmp/size]
			append window tmp
		]
		; Set optional background:
		if any [opts/color opts/draw] [
			insert window make gob! append copy [
				size: window/size
				offset: 0x0
			] pick [
				[draw:  opts/draw]
				[color: opts/color]
			] block? opts/draw
		]
		; Set up default handler, if user did not provide one:
		unless opts/handler [
			handle-events [
				name: 'view-default
				priority: 50
				handler: func [event] [
					print ["view-event:" event/type event/offset]
					switch event/type [
						close [quit]
						key [if event/key = escape [quit]]
					]
					show event/window
					none ; we handled it
				]
			]
		]
	]

	; VID-layout based view:
	if block? window [
		window: layout/background window any [opts/draw opts/color]
	]

	; VID-face based view:
	if object? window [
		; Build the window:
		window: append make gob! [
			data: window
			size: window/size
		] window/gob
		window/options: [resize] ; may be overwritten below
	]

	; Window title:
	window/text: any [opts/title window/text "Rebol: untitled"]

	;!!! Add later: use script title - once modules provide that

	; Other options:
	if opts/offset [
		; 'Center is allowed:
		if word? opts/offset [
			opts/offset: either opts/offset = 'center [screen/size - window/size / 2][100x100]
		]
		window/offset: opts/offset
	]
	; gob/options are called MODES (to avoid confusion)
	if opts/modes [window/options: opts/modes]
	if opts/handler [handle-events opts/handler]

	; Add the window to the screen. If it is already there, this action
	; will move it to the top:
	unless window = screen [append screen window]

	; Open or refresh the window:
	show window

	; Wait for the event port to tell us we can return:
	if all [
		not opts/no-wait
		1 = length? screen
	][
		do-events
	]

	; Return window (which may have been created here):
	window
]

unview: func [
	"Closes a window view."
	window [object! gob! word! none!] "Window face or GOB. 'all for all. none for last"
	/local screen
][
	screen: system/view/screen-gob
	case [
		object? window [window: window/gob/parent]
		window = 'all [show clear screen exit]
		not window [window: last screen] ; NONE is ok
	]
	remove find screen window ; none ok
	show window ; closes it, none ok
]

handle-events: func [
	"Adds a handler to the view event system."
	handler [block!]
	/local sys-hand
][
	handler: context handler
	sys-hand: system/view/event-port/locals/handlers
	; Insert by priority:
	unless foreach [here: hand] sys-hand [
		if handler/priority > hand/priority [
			insert here handler
			break/return true
		]
	][
		append sys-hand handler
	]
	handler
]

unhandle-events: func [
	"Removes a handler from the view event system."
	handler [object!]
][
	remove find system/view/event-port/locals/handlers handler
	exit
]

handled-events?: func [
	"Returns event handler object matching a given name."
	name
][
	foreach hand system/view/event-port/locals/handlers [
		if hand/name = name [return hand]
	]
	none
]

do-events: func [
	"Waits for window events. Returns when all windows are closed."
][
	wait system/view/event-port
]

init-view-system: func [
	"Initialize the View subsystem."
	/local ep
][
	; Already initialized?
	if system/view/event-port [exit]

	; Open the event port:
	ep: open [scheme: 'event]
	system/view/event-port: ep

	; Create block of event handlers:
	ep/locals: context [handlers: copy []]

	; Global event handler for view system:
	ep/awake: func [event /local h] [
		h: event/port/locals/handlers
		while [ ; (no binding needed)
			all [event not tail? h]
		][
			; Handlers should return event in order to continue.
			event: h/1/handler event
			h: next h
		]
		tail? system/view/screen-gob
	]
]

Getting Started With R3 R3 Gui/ Graphical User Interface Pages:
Clone this wiki locally