View in color | License | Download script | History | Other scripts by: christian |
30-Apr 16:14 UTC
[0.076] 37.764k
[0.076] 37.764k
time-line.rREBOL [
Title: "Time-Line"
Name: 'time-line
File: %time-line.r
Version: 0.3.1
Date: 4-Mar-2006
Author: "Christian Ensel"
Email: %christian--ensel--gmx--de
Owner: "Christian Ensel"
Purpose: {
Time-line VID style for use in time-table editing using AGG.
}
History: [
0.3.1 4-Mar-2006 {
- With View 1.3.2 script wasn't working as expected (misplaced gradients), fixed.
- Grabbing the two ends of a period changed from left/right third to quarter width.
}
]
Library: [
level: 'intermediate
platform: 'all
type: [tool demo]
code: 'module
domain: [user-interface vid gui]
tested-under: [
view 1.3.1 on "WinXP"
view 1.3.2 on "WinXP"
]
support: none
license: none
see-also: none
]
]
;===============================================================================
;REBOL [
; title: "collect"
; file: %collect.r
; author: "Brett Handley"
; email: %brett--codeconscious--com
; web: http://www.codeconscious.com
; date: 24-Jul-2003
; purpose: "Accumulate a repeated expression.."
;]
;-------------------------------------------------------------------------------
collect: func [
{Collects block evaluations, use as body in For, Repeat, etc.}
block [block!] "Block to evaluate."
/initial result [series! datatype!] "Initialise the result."
/only "Inserts into result using Only refinement."
] [
if not initial [result: block!]
result: any [all [datatype? result make result 1000] result]
reduce ['head pick [insert insert/only] not only 'tail result to paren! block]
]
;===============================================================================
stylize/master [
time-line: box with [
style: 'time-line
size: 100x100
handle: 0x0
color: none
colors: reduce [none yellow + 0.191.191]
start: 6:00
end: 21:00
data: none
font: make font [name: "Tahoma" size: 8 style: shadow: none]
para: make para [ ;-- Hinder View's caret to be visible if the
origin: -100x-100 ; face gets the focus.
]
resolution: 0:30 ;-- Resolution sets the granularity of edits.
; All edits are stored on a per minute base but
; are rounded before displaying them
pixel-of: func [
"Converts a time value into it's corresponding horizontal pixel offset."
time [time!]
][
size/x - 1 * (time - start) / (end - start)
]
time-of: func [
"Converts a horizontal pixel offset into it's corresponding time value."
pixel [number!]
][
pixel * (end - start) / (size/x - 1) + start
]
edge: none ;-- NOT SUPPORTED!
mouse: 'away ;-- Maybe I could do without this
others: 'may-hover ;-- Two state flag telling other time-line
; faces whether the are allowed to show up
; in hovered state ('MAY-HOVER) or
; not ('NEED-NOT-HOVER).
edit: none ;-- Holds flags 'START and 'END, telling
; whether to resize a period at either it's
; start or end or to move it
active-period: none
selected-periods: none ;-- Block holding all selected period objects
; for multi-edits
words: [
periods [
new/data: second args ;-- Period descriptions will be dialected
next args ; and converted to objects internally.
]
range [
new/start: first second args
new/end: second second args
next args
]
]
drawings: none ;-- The context where all the drawings for
; grid, periods, selected-periods and the cursor
; are kept (initialised in the INIT block).
draw: context [
grid: func ["Draws the hourly, half and quarterly grid." face [object!]] [
face/drawings/grid: any [face/drawings/grid copy []]
insert clear face/drawings/grid for time face/start face/end 1:00 collect [
compose [
pen (face/color / 8)
line-width 0.5
line (as-pair face/pixel-of time 0)
(as-pair face/pixel-of time face/size/y)
pen (face/color / 4)
line-width 0.25
line (as-pair face/pixel-of time + 0:30 0)
(as-pair face/pixel-of time + 0:30 face/size/y)
pen (face/color / 2)
line-width 0.125
line (as-pair face/pixel-of time + 0:15 0)
(as-pair face/pixel-of time + 0:15 face/size/y)
line (as-pair face/pixel-of time + 0:45 0)
(as-pair face/pixel-of time + 0:45 face/size/y)
]
]
]
periods: func [face [object!] /local start end] [
face/drawings/periods: any [face/drawings/periods copy []]
if empty? face/data [clear face/drawings/periods return]
insert clear face/drawings/periods foreach period face/data collect [
start: round/to period/start face/resolution
end: round/to period/end face/resolution
compose [
line-width 0,66
pen (black)
fill-pen linear 0x0 0 (face/size/y - 2) 90 1 1 (period/color + 0.0.0.64)
(255.255.255.64)
(period/color + 0.0.0.64)
(period/color + 0.0.0.32)
(period/color / 2)
(period/color / 4)
box (as-pair face/pixel-of start 3)
(as-pair face/pixel-of end face/size/y - 4) (period/radius)
pen black fill-pen white
font (font)
text (copy/part skip tail join "0" mold start -5 5)
(as-pair 3 + face/pixel-of start face/size/y / 2 - 5)
text (copy/part skip tail join "0" mold end -5 5)
(as-pair -21 + face/pixel-of end face/size/y / 2 - 5)
]
]
]
grip: func [
"Draws the grip." face /local period fill start start? end end? width color
][
face/drawings/grip: any [face/drawings/grip copy []]
if none? period: face/active-period [
clear face/drawings/grip
return
]
start: round/to period/start face/resolution
end: round/to period/end face/resolution
width: (face/pixel-of end) - (face/pixel-of start)
color: period/color / 4 - 0.0.0.255 + 0.0.0.127 ;period/color
;color: gold + 0.0.0.127
start?: found? find period/edit 'start?
end?: found? find period/edit 'end?
fill: compose any [
if all [start? end?] [
;[fill-pen linear (as-pair face/pixel-of start 0) (face/pixel-of start) (width) 0 1 1 (color + 0.0.0.127) (color) (color + 0.0.0.127)] ; + 0.0.0.255) (color + 0.0.0.127) (color + 0.0.0.63) (color) (color + 0.0.0.63) (color + 0.0.0.127) (color + 0.0.0.255)]
[fill-pen linear (as-pair face/pixel-of start 0) 0 (width) 0 1 1 (color + 0.0.0.255) (color) (color) (color + 0.0.0.255)]
]
if start? [
;[fill-pen linear (as-pair face/pixel-of start 0) (face/pixel-of start) (width) 0 1 1 (color) (color + 0.0.0.63) (color + 0.0.0.127) (color + 0.0.0.255)]
[fill-pen linear (as-pair face/pixel-of start 0) 0 (width) 0 1 1 (color) (color + 0.0.0.127) (color + 0.0.0.255) (color + 0.0.0.255)]
]
if end? [
;[fill-pen linear (as-pair face/pixel-of start 0) (face/pixel-of start) (width) 0 1 1 (color + 0.0.0.255) (color + 0.0.0.127) (color + 0.0.0.63) (color)]
[fill-pen linear (as-pair face/pixel-of start 0) 0 (width) 0 1 1 (color + 0.0.0.255) (color + 0.0.0.255) (color + 0.0.0.127) (color)]
]
]
insert clear face/drawings/grip compose [
line-width 1
pen black fill-pen (fill)
box (as-pair face/pixel-of start 3)
(as-pair face/pixel-of end face/size/y - 4) (period/radius)
]
]
cursor: func [
"Draws the cursor."
face [object!] offset [integer! none!] /local period time color
][
color: navy ; + 0.0.0.63
face/drawings/cursor: any [face/drawings/cursor copy []]
clear face/drawings/cursor
if any [
none? offset
face/active-period: face/feel/period? face offset
][
return
]
time: round/to face/time-of offset face/resolution
insert face/drawings/cursor compose [
pen (color) line-width 3
line (as-pair face/pixel-of time 0) (as-pair face/pixel-of time face/size/y)
pen black
font (face/font)
text (copy/part skip tail join "0" mold round/to time 0:01 -5 5) (as-pair -9 + face/pixel-of time face/size/y / 2 - 5)
]
]
selected-periods: func [face /local start end color] [
face/drawings/selected-periods: any [face/drawings/selected-periods copy []]
clear face/drawings/selected-periods
if empty? face/selected-periods [return]
color: navy ;+ 0.0.0.63
insert clear face/drawings/selected-periods foreach period face/selected-periods collect [
start: round/to period/start face/resolution
end: round/to period/end face/resolution
compose [
line-width 3
pen (color) fill-pen none
box (as-pair -2 + face/pixel-of start 1)
(as-pair +2 + face/pixel-of end face/size/y - 2) (period/radius + 3)
(
compose either find period/edit 'start [
[
pen none fill-pen (color)
triangle (as-pair -3 + face/pixel-of start 0)
(as-pair -3 + face/pixel-of start face/size/y)
(as-pair - face/size/y / 2 - 3 + face/pixel-of start face/size/y / 2)
]
][[]]
)
(
compose either find period/edit 'end [
[
pen none fill-pen (color)
triangle (as-pair 4 + face/pixel-of end 0) ;face/size/y - 1 / 3)
(as-pair 4 + face/pixel-of end face/size/y)
(as-pair face/size/y / 2 + 4 + face/pixel-of end face/size/y / 2)
]
][[]]
)
]
]
]
]
feel: make feel [
redraw: func [face action offset] [
either face <> system/view/focal-face [
face/color: face/colors/1
clear face/drawings/selected-periods
][
face/color: face/colors/2
]
face/drawings/grid
]
edit: func [
"Determines the edit mode for the active period." face offset
/local
period start end quarter
][
if none? period: face/active-period [return]
start: face/pixel-of round/to period/start face/resolution
end: face/pixel-of round/to period/end face/resolution
quarter: end - start / 4
any [
if all [start <= offset offset <= (start + quarter)] [
edit-end/data: off edit-start/data: on ;#####
remove find period/edit 'start?
remove find period/edit 'end?
insert period/edit 'start?
]
if all [end - quarter <= offset offset <= end] [
edit-start/data: off edit-end/data: on ;#####
remove find period/edit 'start?
remove find period/edit 'end?
insert period/edit 'end?
]
do [
edit-start/data: edit-end/data: on ;#####
remove find period/edit 'start?
remove find period/edit 'end?
insert period/edit [start? end?]
]
]
show [edit-start edit-end] ;#####
]
period?: func [face offset [pair! time! number! none!] /all] [
if none? offset [return none]
offset: switch type?/word offset [
integer! [face/time-of offset]
decimal! [face/time-of offset]
pair! [face/time-of offset/x]
time! [offset]
]
foreach period face/data [
if (period/start < offset) and (offset < period/end) [break/return period]
]
]
over: func [face over? offset] [
face/selected-periods: any [face/selected-periods copy []]
;-- Don't hover time-line if we're editing another
;
if all [
system/view/focal-face
get in system/view/focal-face 'style
system/view/focal-face/style = 'time-line
system/view/focal-face <> face
system/view/focal-face/others = 'need-not-hover
][
return
]
offset: offset - win-offset? face ;-- Remember, offset argument is relative to window here!
face/feel/edit face offset/x
face/mouse: pick [over away] over?
face/draw/selected-periods face
face/draw/grip face
face/draw/cursor face offset/x
if not over? [
clear face/drawings/cursor
clear face/drawings/grip
]
show face
]
engage: func [face action event /local delta swap edit offset] [
shift-key/data: event/shift show shift-key
control-key/data: event/control show control-key
offset: event/offset - win-offset? face ;-- Remember, offset argument is relative to window here!
face/selected-periods: any [face/selected-periods copy []]
if action = 'key [
if event/key = #"^[" [
foreach period face/selected-periods [
clear period/edit
]
clear face/selected-periods
]
if event/key = #"^A" [
insert clear face/selected-periods face/data
foreach period face/selected-periods [
insert clear period/edit [start end]
]
]
if event/key = 'up [
foreach period face/selected-periods [
insert clear period/edit 'start
if any [event/shift event/control] [
insert period/edit 'end
]
]
]
if event/key = 'down [
foreach period face/selected-periods [
insert clear period/edit 'end
if any [event/shift event/control] [
insert period/edit 'start
]
]
]
if event/key = #"^M" [
clear face/selected-periods
face/active-period: none
]
if find [left right] event/key [
delta: face/resolution * select [left -1 right +1] event/key
foreach period face/selected-periods [
if find period/edit 'start [period/started: period/start: period/start + delta]
if find period/edit 'end [period/ended: period/end: period/end + delta]
if period/start > period/end [
;set bind [start end] in period 'self reduce bind [end start] in period 'self
swap: period/start period/start: period/end period/end: swap
alter period/edit 'start
alter period/edit 'end
edit-start/data: not edit-start/data ;#####
edit-end/data: not edit-end/data ;#####
show [edit-start edit-end]
]
]
]
]
if find [over away] action [
foreach period face/selected-periods [
delta: (face/time-of event/offset/x - face/handle/x) - face/start
if find period/edit 'start [
period/start: round/to period/started + delta face/resolution
]
if find period/edit 'end [
period/end: round/to period/ended + delta face/resolution
]
if period/end < period/start [
swap: period/start period/start: period/end period/end: swap
alter period/edit 'start
alter period/edit 'end
edit-start/data: not edit-start/data ;#####
edit-end/data: not edit-end/data ;#####
show [edit-start edit-end]
]
]
;face/handle: event/offset
face/mouse: action
]
if find [down alt-down] action [
if face <> system/view/focal-face [focus/no-show face]
either face/active-period [
remove find face/active-period/edit 'start
remove find face/active-period/edit 'end
][
either not event/double-click [
clear face/selected-periods
][
insert tail face/data face/active-period: make object! compose [
type: 'unknown
started: start: round/to face/time-of event/offset/x face/resolution
ended: end: round/to face/resolution + face/time-of event/offset/x face/resolution
color: 0.0.0.31 + random white
radius: -1 + random 16
edit: copy [end?]
]
]
]
if not any [event/shift event/control] [
clear face/selected-periods
clear face/drawings/grip
]
if face/active-period [
face/others: 'need-not-hover
if not found? find face/selected-periods face/active-period [
insert face/selected-periods face/active-period
]
if find face/active-period/edit 'start? [insert face/active-period/edit 'start]
if find face/active-period/edit 'end? [insert face/active-period/edit 'end ]
]
face/handle: event/offset
]
if find [up alt-up] action [
foreach period face/data [
period/started: period/start
period/ended: period/end
]
if not any [event/shift event/control] [
clear face/selected-periods
clear face/drawings/grip
]
if face/active-period [
if not found? find face/selected-periods face/active-period [
insert face/selected-periods face/active-period
]
]
;if face/mouse = 'away [clear face/drawings/cursor]
face/others: 'may-hover
]
face/draw/periods face
face/draw/selected-periods face
face/draw/grip face
clear face/drawings/cursor
;if not find [over away] action [
; face/draw/cursor face event/offset/x
;]
show face
]
]
resize: func [new [pair!]] [
;size: max 90x12 new
size: new
draw/grid self
draw/periods self
draw/selected-periods self
draw/grip self
]
init: copy [
data: any [data copy []]
color: any [color white]
colors/1: color
selected-periods: copy []
edit: copy []
drawings: context [grid: periods: selected-periods: grip: cursor: none]
draw/grid self
draw/periods self
draw/selected-periods self
draw/grip self
draw/cursor self none
effect: compose/only [draw (drawings/grid) draw (drawings/selected-periods) draw (drawings/periods) draw (drawings/grip) draw (drawings/cursor)]
]
]
]
;################################ DEMO #########################################
;
change-grid: func [resolution [time!]] [
foreach face time-lines/pane [
face/resolution: resolution
foreach period face/data [
period/started: period/start: round/to period/start resolution
period/ended: period/end: round/to period/end resolution
]
face/draw/periods face
face/draw/selected-periods face
show face
]
]
window: center-face layout compose/deep [
across space 8x1
text "Working:" bold return
pad 24x0 text "- Double click to create new periods." return
pad 24x0 text "- Use cursor keys, CTRL+A and ESC for keyboard editing (incomplete)." return
pad 0x24
text "To do:" bold return
pad 24x0 text "- Currently, you can't resize 0-width periods (events)" return
pad 24x0 text "- Swapping start and end times produces unexpected results for now" return
pad 24x0 text "- Think about collision detection!" return
pad 24x0 text "- Think about period names!" return
pad 24x0 text "- Period dialect" return
pad 0x24
text "Resolution:" bold
radio-line "0:01 h" of 'grid [change-grid 0:01]
radio-line "0:05 h" of 'grid [change-grid 0:05]
radio-line "0:15 h" of 'grid [change-grid 0:15]
radio-line "0:30 h" of 'grid [change-grid 0:30] on
radio-line "1:00 h" of 'grid [change-grid 1:00]
pad 80
text "Edit Mode:" bold
edit-start: check-line "start" of 'mode
edit-end: check-line "end" of 'mode
pad 80
text "Modifiers:" bold
shift-key: check-line "Shift"
control-key: check-line "Control"
return
panel [
across
panel [
space 1x1 origin 1x1
btn 48x24 "Mo."
btn 48x24 "Di."
btn 48x24 "Mi."
btn 48x24 "Do."
btn 48x24 "Fr."
btn 48x24 "Sa." 255.223.223
btn 48x24 "So." 255.191.191
]
time-lines: panel [
space 1x1 origin 1x1
time-line 960x24 periods [
(context [type: 'work started: start: 07:00 ended: end: 10:00 color: 255.255.255.031 radius: 4 edit: []])
(context [type: 'away started: start: 10:00 ended: end: 16:00 color: 063.127.255.031 radius: 8 edit: []])
]
time-line 960x24 periods [
(context [type: 'away started: start: 09:00 ended: end: 12:00 color: 063.127.255.031 radius: 8 edit: []])
(context [type: 'work started: start: 12:00 ended: end: 14:00 color: 255.127.063.031 radius: 4 edit: []])
(context [type: 'ill started: start: 16:00 ended: end: 18:00 color: 063.255.127.031 radius: 4 edit: []])
]
time-line 960x24 periods []
time-line 960x24 periods []
time-line 960x24 periods []
time-line 960x24 periods [] 255.223.223 range [0:00 24:00]
time-line 960x24 periods [] 255.191.191 range [0:00 24:00]
]
]
]
if request/confirm {
You may try the time-line with or without Romano Paolo Tenca's RESIZE-VID script.
Do you want to do-thru http://www.rebol.it/~romano/resize-vid.r now?
} [
do-thru http://www.rebol.it/~romano/resize-vid.r
window: auto-resize window
]
view/options window [resize all-over] Notes
|