chat: make rebface [ tip: { USAGE: chat 140x50 chat data ["Bob" blue "My comment." yello 14-Apr-2007/10:58] DESCRIPTION: Three column chat display as found in IM apps such as AltME. Messages are appended, with those exceeding 'limit not shown. OPTIONS: [limit n] where n specifies number of messages to show (default 100) [id n] where n specifies id column width (default 10) [user n] where n specifies user column width (default 15) [date n] where n specifies date column width (default 25) } size: 200x100 pane: [] data: [] edge: outline-edge action: make default-action [ on-resize: make function! [face] [ poke face/pane/2/para/tabs 3 face/pane/1/size/x - (sizes/cell * any [select face/options 'date 25]) face/redraw/no-show ] ] height: 0 ; actual pixel height of all messages (-1 ensures first message is offset to hide it's edge rows: 0 ; number of messages limit: none ; last n messages to display append-message: make function! [ user [string!] user-color [tuple! word! none!] msg [string!] msg-color [tuple! word! none!] date [date!] /no-show row /local p y t1 t2 t3 ][ ; cache current tab stops t1: pick pane/2/para/tabs 1 t2: pick pane/2/para/tabs 2 t3: pick pane/2/para/tabs 3 ; get height of message y: max sizes/line 4 + second size-text make subface [ size: as-pair t3 - t2 10000 text: msg font: default-font para: default-para-wrap ] p: self insert tail pane/1/pane reduce [ make subface [ offset: as-pair 0 height size: as-pair t1 y text: form any [row rows: rows + 1] color: colors/theme-dark edge: make outline-edge [size: 0x1] font: default-font-heading ] make subface [ offset: as-pair t1 height size: as-pair t2 - t1 y text: user edge: make outline-edge [size: 0x1] font: make default-font-top [color: either word? user-color [get user-color] [user-color] style: 'bold] ] make subface [ offset: as-pair t2 height size: as-pair t3 - t2 y span: all [p/span find p/span #W #W] text: form msg color: either word? msg-color [get msg-color] [msg-color] edge: make outline-edge [size: 0x1] font: default-font para: default-para-wrap ] make subface [ offset: as-pair t3 height size: as-pair p/size/x - t3 - sizes/slider y span: all [p/span find p/span #W #X] text: form either now/date = date/date [date/time] [date/date] edge: make outline-edge [size: 0x1] font: default-font-top ] ] height: height + y - 1 if ((length? pane/1/pane) / 4) > limit [ y: pane/1/pane/1/size/y - 1 remove/part pane/1/pane 4 foreach [i u m d] pane/1/pane [ i/offset/y: u/offset/y: m/offset/y: d/offset/y: i/offset/y - y ] height: height - y ] unless no-show [ insert tail data reduce [user user-color msg msg-color date] pane/1/size/y: height pane/3/ratio: pane/3/size/y / height show p ] show pane/1 ; !!! this cleans up artifacts but "eats" other widgets redraw events !!! ] set-user-color: make function! [id [integer!] color [tuple! word! none!] /local idx] [ if any [zero? id id > rows] [exit] poke data id * 5 - 3 color if limit > (rows - id) [ idx: either rows > limit [(id + limit - rows) * 4 - 2] [id * 4 - 2] pane/1/pane/:idx/font/color: either word? color [get color] [color] show pane/1/pane/:idx ] ] set-message-text: make function! [id [integer!] string [string!] /local idx] [ if any [zero? id id > rows] [exit] poke data id * 5 - 2 string if limit > (rows - id) [ idx: either rows > limit [(id + limit - rows) * 4 - 1] [id * 4 - 1] insert clear pane/1/pane/:idx/text string redraw ] ] set-message-color: make function! [id [integer!] color [tuple! word! none!] /local idx] [ if any [zero? id id > rows] [exit] poke data id * 5 - 1 color if limit > (rows - id) [ idx: either rows > limit [(id + limit - rows) * 4 - 1] [id * 4 - 1] pane/1/pane/:idx/color: either word? color [get color] [color] show pane/1/pane/:idx ] ] redraw: make function! [/no-show /local row] [ clear pane/1/pane height: 0 rows: (length? data) / 5 row: max 0 rows - limit: any [select options 'limit 100] foreach [user user-color msg msg-color date] skip data row * 5 [ append-message/no-show user user-color msg msg-color date row: row + 1 ] pane/1/size/y: height pane/3/ratio: either zero? height [1] [pane/3/size/y / height] unless no-show [show self] ] init: make function! [/local p] [ p: self limit: any [select options 'limit 100] insert pane make subface [ offset: as-pair 0 sizes/line size: p/size - as-pair sizes/slider sizes/line span: all [p/span find p/span #W #W] pane: [] ] ; heading insert tail pane make subface [ size: as-pair p/size/x sizes/line text: "ID^-User^-Message^-Sent" span: all [p/span find p/span #W #W] color: colors/theme-dark font: make default-font [color: colors/page] para: make default-para [tabs: [0 0 0]] ] ; set header tabs poke pane/2/para/tabs 1 sizes/cell * any [select options 'id 10] poke pane/2/para/tabs 2 sizes/cell * (any [select options 'user 15]) + pick pane/2/para/tabs 1 poke pane/2/para/tabs 3 size/x - sizes/slider - (sizes/cell * any [select options 'date 25]) ; vertical scroller insert tail pane make slider [ tip: none offset: as-pair p/size/x - sizes/slider sizes/line size: as-pair sizes/slider p/size/y - sizes/line span: case [ none? p/span [none] all [find p/span #H find p/span #W] [#XH] find p/span #H [#H] find p/span #W [#X] ] options:[arrows] action: make default-action [ on-click: make function! [face /local p] [ p: face/parent-face p/pane/1/offset/y: sizes/line + negate (height - face/size/y) * face/data show p ] ] ] pane/3/init action/on-resize self ] ]