|
Form Designer - Source CodeDesign and run simple forms with a WYSIWYG editor. |
|
REBOL [ Title: "RebForms" Author: "Ashley Truter <ashley@dobeash.com>" Purpose: "REBOL/View Form Designer." Date: 26-Mar-2004 Version: 1.0 Copyright: "©2004 Dobeash Investments Pty Ltd" Licence: "Free for both commercial and non-commercial use." ] ; ---------------------------------------- ; VID Patches ; ---------------------------------------- ; colour of text-list/picked ; http://www.rebol.org/cgi-bin/cgiwrap/rebol/ml-display-thread.r?m=rmlNJXK svvc/field-select: sky ; [view] changing window title. -- vid 1.3 -- ; http://www.rebol.org/cgi-bin/cgiwrap/rebol/ml-display-thread.r?m=rmlQGLQ set-title: func [ "Sets title bar of window" face [object!] "Window dialog face" title [string!] "Window bar title" ][ face/text: title face/changes: 'text show face ] ; Area bug? ; http://www.rebol.org/cgi-bin/cgiwrap/rebol/ml-display-thread.r?m=rmlMZJJ stylize/master [ area: area wrap with [insert tail init [para: make para []]] field: field middle with [insert tail init [para: make para []]] info: info middle with [feel: none] label: label middle with [feel: none] text: text middle with [feel: none] ] ; simple dialog wrapper for view, center-face, layout dialog: function [ "Displays a window face with a pane built from style description dialect." title [string!] "Window bar title" specs [block!] "Dialect block of styles, attributes, and layouts" ][ face ][ either empty? system/view/screen-face/pane [ view/new/title center-face layout specs title ][ face: last system/view/screen-face/pane view/new/title/options/offset layout specs title compose [ parent (first system/view/screen-face/pane) ] face/offset + 0x28 ] ] ; ---------------------------------------- ; Styles ; ---------------------------------------- svsf: system/view/screen-face to-width: func [x [integer!]] [ GUI/element/x + GUI/spacing/x * x - GUI/spacing/x ] to-size: func [size [pair!]] [ as-pair GUI/element/x + GUI/spacing/x * size/x - GUI/spacing/x GUI/element/y + GUI/spacing/y * size/y - GUI/spacing/y ] stylize/master [ field: field edge [size: 1x1 color: black effect: none] [trim face/text show face] label: label black font [shadow: none] title: txt font [valign: 'middle align: 'center] check: face with [ size: 24x24 color: white font: [name: "Wingdings" align: 'center valign: 'bottom style: 'bold shadow: none colors: reduce [leaf leaf]] image: effects: para: none edge: [size: 1x1 color: black effect: none] feel: make svvf/toggle [ redraw: func [face act pos] [ face/text: either face/state [face/texts/2] [face/texts/1] ] ] flags: [toggle] init: [ edge: make edge [] font: make font [] font/size: to integer! size/y * .75 font/color: first font/colors texts: copy ["" "ü"] ] ] ; file: %dropdown.r ; date: 20-Feb-2004 ; title: "VID Dropdown" ; author: "Ammon Johnson" drop-down: face with [ size: 100x24 color: white get-selected: lay-options: options: unview-options: none words: [ data [new/data: first next args next args] ] resize: func [new /arrow arr-size] [ size: new if arrow [pane/2/size/x: arr-size] pane/1/size: new - as-pair pane/2/size/x 0 pane/2/size/y: new/y pane/2/offset: new - pane/2/size options/size/x: size/x options/sub-area/size/x: pane/1/size/x options/sld/size/x: pane/2/size/x + pane/2/edge/size/x options/sld/offset/x: pane/1/size/x lay-options/size/x: size/x options/data: data ; to work with VID 1.3 ] init: [ lay-options: layout [ origin 0x0 options: text-list #"^(ESC)" (size + 0x150 )[ if not empty? options/picked [ pane/1/text: copy first options/picked ; added ESC and copy ] show pane/1 unview/only lay-options remove-event-func :unview-options action pane/1 pane/1/text ] ] lay-options/options: reduce ['no-border 'no-title 'parent self] unview-options: func [f "face" e "event"] [ if all [e/type = 'inactive e/face = lay-options] [ unview/only lay-options remove-event-func :unview-options ] e ] get-selected: does[ options/lines: data options/update lay-options/offset: (screen-offset? pane/1) + as-pair 0 size/y insert-event-func :unview-options view/new lay-options ] pane: reduce [ ; added color support make-face/spec 'field compose/deep [ color: (color) colors: [(color) (color)] edge: none ] make-face/spec 'arrow [ size: 16x16 data: 'down action: [get-selected] ] ] if text [pane/1/text: text] if none? data [data: texts] if none? data [data: copy []] ; if not found? find data text [insert data text text: none] resize size ] ] ] set-styles: does [ ; Element sizes stylize/master [ ; Standard btn: btn to-size 1x1 font-size to-integer GUI/fontsize sbtn: btn GUI/element / 2x1 font-size to-integer GUI/fontsize bar: bar to-width 1 field: field to-size 1x1 font-size GUI/fontsize GUI/Backcolor GUI/Backcolor info: info to-size 1x1 font-size GUI/fontsize label: label to-size 1x1 font-size GUI/fontsize text: text to-size 1x1 font-size GUI/fontsize title: title to-size 1x1 font-size GUI/fontsize navy pewter bold tog: tog to-size 1x1 font-size to-integer GUI/fontsize stog: tog GUI/element / 2x1 font-size to-integer GUI/fontsize ; Base action buttons btn-yes: btn "Yes" btn-no: btn "No" [unview/only face/parent-face/self] btn-ok: btn "OK" btn-cancel: btn "Cancel" [unview/only face/parent-face/self] btn-close: btn "Close" [unview/only face/parent-face/self] btn-exit: btn "Exit" [quit] ; Special area: area to-size 2x2 font-size GUI/fontsize GUI/Backcolor GUI/Backcolor check-line: check-line to-size 1x1 radio-line: radio-line to-size 1x1 check: check as-pair GUI/element/y GUI/element/y radio: radio as-pair GUI/element/y GUI/element/y txt: txt font-size GUI/fontsize ] ] GUI: context [ backcolor: white fontsize: none element: none spacing: 8x8 margin: 20x20 imagesize: none x1: x2: x3: x4: x5: x6: x7: x8: none get-text-size: has [t][ layout [t: txt font-size fontsize "MMMMMMMM"] size-text t ] set-fontsize: func [size [integer!]][ if size <> fontsize [ if odd? size [size: size - 1] fontsize: max 12 min size 36 ; Set element size to an even pair element: 8x4 + get-text-size element/y: to-integer element/y * 1.2 ; 20% vertical margin element/y: max element/y 22 ; minimum y of 22 (btn bitmap height) if odd? element/x [element/x: element/x + 1] if odd? element/y [element/y: element/y + 1] ; set rest spacing: as-pair fontsize / 2 fontsize / 2 margin: as-pair fontsize fontsize x1: to-size 1x1 x2: to-size 2x1 x3: to-size 3x1 x4: to-size 4x1 x5: to-size 5x1 x6: to-size 6x1 x7: to-size 7x1 x8: to-size 8x1 set-styles ] ] ] GUI/set-fontsize 12 ;to integer! svsf/size/x / 64 ; ---------------------------------------- ; Main Program Code ; ---------------------------------------- designer: context [ main-out: none ; align radio-align: 'lm ; cell size cell-size: 16x16 ; pointer to current object nub-obj: none ; active object nub-face: make face [ offset: 0x0 size: 0x0 edge: make edge [color: 255.0.0 effect: 'nubs size: 4x4] text: color: font: para: data: none feel: make feel [ engage: func [f a e] [ if all [empty? p/move-list data][data/feel/engage data a e] ] ] ] ; update after move / resize update-nubs: func [f] [ nub-face/offset: f/offset ; - 3x3 nub-face/size: f/size ;+ 6x6 ] ; default feel for designer objects nub-feel: [ engage: func [f a e][ if find [over away] a [ either f/data [ f/offset: f/offset + e/offset - f/data f/offset: min max 0x0 f/offset / cell-size * cell-size cell-size * 23x31 f/offset: confine f/offset f/size 0x0 cell-size * 24x32 ][ f/size: (cell-size / 2) + e/offset / cell-size * cell-size if f/size/x < cell-size/x [f/size/x: cell-size/x] if f/size/y < cell-size/y [f/size/y: cell-size/y] if (f/offset/x + f/size/x) > (cell-size/x * 24) [f/size/x: (cell-size/x * 24) - f/offset/x] if (f/offset/y + f/size/y) > (cell-size/y * 32) [f/size/y: (cell-size/y * 32) - f/offset/y] ] update-nubs f show [f nub-face] ] if find [down alt-down] a [ nub-obj: f f/data: e/offset - (cell-size / 2) update-nubs f nub-face/data: f show f/parent-face ; set properties cell-type/text: form f/var cell-name/text: form f/text cell-link/text: form f/text cell-edge/data: either zero? f/edge/size [false][true] cell-color/data: either f/color = silver [true][false] hide b switch/default f/var [ Field [ hide [cell-name cell-edge cell-color lt ct rt lm cm rm lb cb rb] show [cell-type cell-link cell-edge cell-color] ] Check [ hide [cell-link cell-name cell-edge cell-color lt ct rt lm cm rm lb cb rb] show cell-type ] Diagram [ hide [cell-name cell-edge cell-color lt ct rt lm cm rm lb cb rb] show [cell-type cell-link] ] ][ ; hide previous radio selection designer/:radio-align/data: false ; show current radio selection radio-align: to-word join first form f/font/align first form f/font/valign designer/:radio-align/data: true ; Heading / Label hide cell-link show [cell-type cell-name cell-edge cell-color lt ct rt lm cm rm lb cb rb] ] ; don't allow resize on check / diagram if all [a = 'alt-down not find [Check Diagram] f/var][f/data: none] ] ] ] get-offset: has [offset][ offset: negate cell-size/y foreach obj next p/pane [ offset: max offset obj/offset/y ] offset: min offset 30 * cell-size/y as-pair 0 (offset + cell-size/y) / cell-size/y ] make-heading: func [/load blk [block!]][ if not load [ blk: copy [] insert blk reduce [ get-offset 4x1 "Heading" silver 0x0 'left 'middle ] ] make face [ offset: blk/1 * cell-size size: blk/2 * cell-size text: blk/3 color: blk/4 edge: make edge [size: blk/5 color: black] font: make font [align: blk/6 valign: blk/7 size: cell-size/x - 4 style: 'bold] para: none feel: make feel nub-feel var: 'Heading ] ] make-label: func [/load blk [block!]][ if not load [ blk: copy [] insert blk reduce [ get-offset 3x1 "Label" white 1x1 'left 'middle ] ] make face [ offset: blk/1 * cell-size size: blk/2 * cell-size text: blk/3 color: blk/4 edge: make edge [size: blk/5 color: black] font: make font [align: blk/6 valign: blk/7 size: cell-size/x - 6] para: none feel: make feel nub-feel var: 'Label ] ] make-field: func [/load blk [block!]][ if not load [ blk: copy [] insert blk reduce [ get-offset 3x1 "" white 1x1 'center 'middle ] ] make face [ offset: blk/1 * cell-size size: blk/2 * cell-size text: blk/3 color: blk/4 edge: make edge [size: blk/5 color: black] font: make font [align: blk/6 valign: blk/7 size: 10 color: blue style: 'underline] para: none feel: make feel nub-feel var: 'Field ] ] make-check: func [/load blk [block!]][ if not load [ blk: copy [] insert blk reduce [ get-offset 1x1 "ü" white 1x1 'center 'bottom ] ] make face [ offset: blk/1 * cell-size size: blk/2 * cell-size text: blk/3 color: blk/4 edge: make edge [size: blk/5 color: black] font: make font [align: blk/6 valign: blk/7 size: cell-size/x - 4 color: leaf name: "Wingdings" style: 'bold] para: none feel: make feel nub-feel var: 'Check ] ] make-diagram: func [/load blk [block!]][ if not load [ blk: copy [] insert blk reduce [ get-offset 2x1 "" white 0x0 'center 'middle ] ] make face [ offset: blk/1 * cell-size size: blk/2 * cell-size text: blk/3 color: blk/4 edge: make edge [size: blk/5 color: black] font: make font [align: blk/6 valign: blk/7 size: 10 color: blue style: 'underline] para: none feel: make feel nub-feel var: 'Diagram image: btn-up.png effect: compose [extend 22 colorize 255.205.40] ] ] lt: ct: rt: lm: cm: rm: lb: cb: rb: none b: p: cell-type: cell-name: cell-link: cell-color: cell-edge: none hide-nub: does [ nub-face/offset: nub-face/size: 0x0 show [b p] ] show-request-file: function [type [string!]][file][ if file: switch type [ "Open" [request-file/title/filter/keep/only "Open Form" "" "*.frm"] "New" [request-file/title/filter/keep/only/file "New Form" "" "*.frm" "new.frm"] "Save" [request-file/title/filter/keep/only/file/save "Save Form" "" "*.frm" "new.frm"] ][ if %.frm <> suffix? file [file: join file %.frm] set-title main-out rejoin ["Designer [" to-local-file file "]"] ] file ] run-form: function [file][to-size page type offset size text color edge align valign][ page: copy [origin 16 space 0 backcolor white] to-size: func [size][ 8x8 + cell-size * size - 4x4 ] foreach blk load/all file [ set [type offset size text color edge align valign] blk insert tail page compose [at (8x8 + cell-size * offset + 16x16)] insert tail page switch type [ Heading [compose/deep [label (to-size size) (text) black (color) (align) (valign) edge [size: (edge) color: black]]] Label [compose/deep [text (to-size size) (text) black (color) (align) (valign) edge [size: (edge) color: black]]] Field [ either size/y > 1 [ compose/deep [area (to-size size) (color) (color) edge [size: (edge) color: black]] ][ either empty? text [ compose/deep [field (to-size size) (color) (color) edge [size: (edge) color: black]] ][ compose/deep [drop-down (to-size size) (color) edge [size: (edge) color: black effect: none] data [(read/lines to-file text)]] ] ] ] Check ['check] Diagram [ either empty? text [ compose [btn (to-size size) "-"] ][ compose/deep [ btn (to-size size) (text) [dialog (text) [origin 0 space 0 image (to-file text)]] ] ] ] ] ] dialog "Run" page ] show-form: has [col row here file blk save-btn][ file: none main-out: dialog "Designer" [ across origin 8x8 ; actions sbtn "New" [ if file: show-request-file face/text [ insert clear p/pane nub-face hide-nub ] ] sbtn "Open" [ file: show-request-file face/text if all [file exists? file][ insert clear p/pane nub-face ; back tail ensures nub-face is last (on top) ; next blk ensures var is not passed foreach blk load/all file [ switch first blk [ Heading [insert back tail p/pane make-heading/load next blk] Label [insert back tail p/pane make-label/load next blk] Field [insert back tail p/pane make-field/load next blk] Check [insert back tail p/pane make-check/load next blk] Diagram [insert back tail p/pane make-diagram/load next blk] ] ] hide-nub ] ] col: at save-btn: sbtn "Save" [ if (length? p/pane) = 1 [ alert rejoin ["Nothing to " lowercase face/text "."] return ] if all [not file not file: show-request-file face/text][ alert "Form not saved." return ] blk: copy [] ; skip first object (nub) foreach obj p/pane [ ; type ; offset ; size ; text ; color ; edge ; align ; valign if obj/text [ insert/only tail blk reduce [ obj/var obj/offset / cell-size obj/size / cell-size obj/text obj/color obj/edge/size obj/font/align obj/font/valign ] ] ] ; can't use save as lines indent write file trim/lines mold/only blk ] sbtn "Undo" [ if (length? p/pane) > 1 [ remove back back tail p/pane hide-nub ] ] sbtn "Run" [ save-btn/action face 0 if all [(length? p/pane) > 1 file exists? file][ run-form file ] ] sbtn "Help" [ dialog "Help" [ image svv/image-stock/help label GUI/x6 "Introduction" txt to-width 6 "This script, extracted from a larger commercial application, allows you to create, save and run simple forms without actually doing anything with the data." label GUI/x6 "Placing / sizing form elements" txt to-width 6 "Clicking a sky colored button will place the corresponding element on the form. Move the element by left-mouse dragging it, or resize by right-mouse drag." label GUI/x6 "Moving a group of elements" txt to-width 6 "Right-mouse drag on the grid to select a number of elements to group. Left-mouse drag outside the grouped elements to move them." label GUI/x6 "Element properties" txt to-width 6 "Clicking a form element displays its modifiable properties to the left of the main grid. The top label indicates the type of element, while a field below this (for Heading / Label elements) allows the element text to be changed. Field / Image elements have a button instead that allows you to assign a list of values (for a Field) or an image (for an Image)." label GUI/x6 "Running your form" txt to-width 6 "Clicking 'Run' will run your form, allowing you to enter data into fields and enabling a pick-list if a list of values was specified. Clicking a check box will toggle its state, while clicking a diagram will display the associated image, if any." txt "" txt to-width 6 "©2004 Dobeash Investments Pty Ltd" bar to-width 6 btn-close ] ] sbtn sky "Head" [insert back tail p/pane make-heading show p] sbtn sky "Label" [insert back tail p/pane make-label show p] sbtn sky "Field" [insert back tail p/pane make-field show p] sbtn sky "Check" [insert back tail p/pane make-check show p] sbtn sky "Image" [insert back tail p/pane make-diagram show p] below ; properties row: at cell-type: text "Heading" bold bar here: at cell-name: field [ nub-obj/text: copy face/text show nub-obj ] at here cell-link: btn white [ if face/data: either nub-obj/var = 'Field [ request-file/title/filter/keep/only "Text List" "" "*.txt" ][ request-file/title/filter/keep/only "Image File" "" ["*.png" "*.jpg" "*.bmp" "*.gif"] ][ face/text: form last split-path face/data nub-obj/text: copy face/text show nub-obj ] ] cell-edge: check-line "Border" [ nub-obj/edge/size: either zero? nub-obj/edge/size [1x1][0x0] show nub-obj ] cell-color: check-line "Fill" [ nub-obj/color: either nub-obj/color = white [silver][white] show nub-obj ] bar across space 0x0 pad 12 lt: radio [radio-align: face/var nub-obj/font/align: 'left nub-obj/font/valign: 'top show nub-obj] ct: radio [radio-align: face/var nub-obj/font/align: 'center nub-obj/font/valign: 'top show nub-obj] rt: radio [radio-align: face/var nub-obj/font/align: 'right nub-obj/font/valign: 'top show nub-obj] return pad 12 lm: radio [radio-align: face/var nub-obj/font/align: 'left nub-obj/font/valign: 'middle show nub-obj] cm: radio [radio-align: face/var nub-obj/font/align: 'center nub-obj/font/valign: 'middle show nub-obj] rm: radio [radio-align: face/var nub-obj/font/align: 'right nub-obj/font/valign: 'middle show nub-obj] return pad 12 lb: radio [radio-align: face/var nub-obj/font/align: 'left nub-obj/font/valign: 'bottom show nub-obj] cb: radio [radio-align: face/var nub-obj/font/align: 'center nub-obj/font/valign: 'bottom show nub-obj] rb: radio [radio-align: face/var nub-obj/font/align: 'right nub-obj/font/valign: 'bottom show nub-obj] ; quick hide at row b: box svv/vid-face/color to-size 1x8 ; page at as-pair first col second row image as-pair cell-size/y * 2 cell-size/y * 34 + 1 make image! layout [ backdrop effect [gradient 1x0 20.20.20 250.240.230 luma 60] ] ; main form design grid with rubber-band feel p: box edge [size: cell-size color: white] cell-size * 26x34 + 1x1 white effect compose [grid (cell-size) (cell-size) (sky)] with [ move-list: copy [] old-offset: none event-offset: none pane: copy [] feel: make feel [ engage: func [f a e][ if find [over away] a [ event-offset: (e/offset + (cell-size / 2)) / cell-size * cell-size either empty? move-list [ nub-face/size: max cell-size absolute event-offset - nub-face/data nub-face/offset: min nub-face/data event-offset ][ old-offset: nub-face/offset nub-face/offset: nub-face/offset + event-offset - nub-face/data nub-face/offset: confine nub-face/offset nub-face/size 0x0 cell-size * 24x32 ; skip rubber-band foreach pos move-list [ pane/:pos/offset: pane/:pos/offset + nub-face/offset - old-offset ] nub-face/data: event-offset ] show p ] if a = 'alt-down [ clear move-list nub-face/offset: nub-face/data: e/offset / cell-size * cell-size nub-face/size: cell-size show p ] if a = 'down [ nub-face/data: e/offset / cell-size * cell-size if empty? move-list [nub-face/offset: nub-face/data] show p ] if a = 'alt-up [ clear move-list repeat pos (length? p/pane) - 1 [ if all [ inside? nub-face/offset + nub-face/size pane/:pos/offset inside? nub-face/offset + nub-face/size + 1x1 pane/:pos/offset + pane/:pos/size inside? pane/:pos/offset + 1x1 nub-face/offset ][insert tail move-list pos] ] if empty? move-list [hide-nub] ] if a = 'up [clear move-list hide-nub] ] ] ] do [insert p/pane nub-face] ] ] ] designer/show-form do-events quit |