############################################################################ # # File: colorway.icn # # Subject: Procedures to manipulate color ways # # Author: Ralph E. Griswold # # Date: August 3, 2000 # ############################################################################ # # This file is in the public domain. # ############################################################################ # # Note: This file contains procedures that can be linked by programs # to add a visual interface, including programs that have one of their # own. # # These procedures support the interactive creation and modification of # color ways. ("Color way" is a the term used in the fashion industry for # a list of colors used in coordination for fabric design or other # decorative purposes. Think color scheme if you like.) # ############################################################################ # # A color way is represented by a list of color specifications. A # color specification consists of a name and an associated color. # Color ways are presented in alphabetical order of their color names, # with the name at the left and a swatch for the corresponding color # at the right of the name. # # The "edit" button is used to switch between two modes: control and # edit. # # In the control mode, the interface menus and the "edit" button # are available. The "File" menu provides for creating a new color # way, loading an existing color way from a file, and saving the # current color way. (Only one color way can be manipulated at a time.) # A new color way starts empty. There also is an item to pick a colorway # file (which must have suffix "cw"). # # The "Ways" menu allows adding and deleting color specifications from # the current color way. When adding, a name dialog is presented first, # followed by a color dialog. Color specifications are added until # the user cancels one of the dialogs. When deleting, all of the # current color specifications are listed by name, and more than one # can be selected for deletion. # # In the edit mode, changes can be made to the current color way. This is # done in the window displaying the current color way. Clicking on a name # in the color way window produces a dialog to change that name. (The new # name cannot be one already in use in the color way.) Clicking on a # color swatch to the right of a name beings up a color dialog for selecting # a new color for that name. (The same color can appear in more than one # color specification.) # # In the editing mode, pressing the meta key while clicking on a # line of the color way causes the color to be deleted. # # The editing mode is exited by typing a "q" in the color way display # window. # # Shortcuts exist for all interface features. @E is a shortcut for # entering the edit mode. # # Note: The current mode is shown by the "edit" button, which is high- # lighted when in the edit mode. There nonetheless can be confusion about # the current mode. # # Unimplemented feature: Prompting user to save color way that has been # modified since last save. # ############################################################################ # # See also: cw.icn # ############################################################################ # # Requires: Version 9 graphics, UNIX for "pick feature" # ############################################################################ # # Links: interact, io, lists, strings, tables, vsetup, xcode # ############################################################################ link interact link io link lists link strings link tables link vsetup link xcode global cw_active # edit-mode switch global cw_active_vidget # edit-mode vidget global cw_touched global cw_vidgets global cw_root global cw # current color way global cw_file # file name for current color way global cw_names # list of color way names global cw_col # position of color field in cw_win global cw_win # window for current cw global cw_interface # interface window global cw_yoff # y offset from top of interface window record colorway(table) # note: "table" does not conflict # with the function name. The # field contains a table. $define ui cw_ui # to avoid conflict with other VIB interfaces $define ui_atts cw_ui_atts $define Pad 10 # name padding $define Lheight 30 # line height $define Cwidth 100 # color width procedure cw_init() local atts atts := ui_atts() put(atts, "posx=10", "posy=10") cw_interface := (WOpen !atts) | stop("can't open window") cw_vidgets := ui() # set up vidgets cw_yoff := WAttrib(cw_interface, "height") + 45 cw_root := cw_vidgets["root"] cw_active_vidget := cw_vidgets["active"] cw_active := &null # initially inactive return end procedure edit_cw() local name expose(cw_win) repeat { case Event(cw_win) of { &lpress | &mpress | &rpress: { name := cw_names[(&y / Lheight) + 1] if &meta then { delete(cw.table, name) cw_touched := 1 win_cw() } else if &x > cw_col then { if ColorDialog("Select color:", cw.table[name]) == "Cancel" then next cw.table[name] := dialog_value cw_touched := 1 win_cw() } else { repeat { if TextDialog("Change name:", , name, 60) == "Cancel" then break if dialog_value[1] == name then break # no change if member(cw.table, dialog_value[1]) then { Notice("Name " || image(dialog_value[1]) || " exists") next } else { cw.table[dialog_value[1]] := cw.table[name] delete(cw.table, name) win_cw() cw_touched := 1 break } } } } "q": return control_mode() } } end procedure control_mode() VSetState(cw_active_vidget, &null) expose(cw_interface) return end procedure active_cb(vidget, value) cw_active := value return end procedure way_cb(vidget, value) case value[1] of { "add @A": add_way() "delete @D": delete_way() } return end procedure file_cb(vidget, value) case value[1] of { "load @L": load_cw() "new @N": new_cw() "pick @P": pick() "quit @Q": quit() "save @S": save_cw() "save as": save_cw_as() } return end procedure shortcuts(e) if &meta then case map(e) of { "a": add_way() "d": delete_way() "e": VSetState(cw_active_vidget, 1) "l": load_cw() "n": new_cw() "p": pick() "q": quit() "s": save_cw() } return end procedure add_way() local name repeat { repeat { if TextDialog("Add color:", "name", , 60) == "Cancel" then return if \cw.table[dialog_value[1]] then { Notice("Name is in use.") next } name := dialog_value[1] if ColorDialog("Choose color:") == "Cancel" then return cw.table[name] := dialog_value win_cw() cw_touched := 1 next } } end # NOTE: Got error in line comparing dialog_value[i]: &null. procedure delete_way() local i, x, count if ToggleDialog("Delete ways:", cw_names) == "Cancel" then fail count := 0 every i := 1 to *dialog_value do if dialog_value[i] == 1 then { delete(cw.table, cw_names[i]) count +:= 1 cw_touched := 1 } if count > 0 then win_cw() return end procedure load_cw() local input, x repeat { if OpenDialog() == "Cancel" then fail input := open(dialog_value) | { Notice("Cannot open file") next } x := xdecodet(input, "colorway") | { Notice("File does not contain color way") close(input) next } cw_file := dialog_value cw := x win_cw() expose(cw_interface) close(input) cw_touched := &null return } end procedure win_cw() local y, name, height WClose(\cw_win) cw_col := 2 * Pad # in case the color way is empty cw_names := (keylist(cw.table) | []) cw_col := maxlen(cw_names, TextWidth) + (2 * Pad) height := Lheight height <:= Lheight * *cw.table cw_win := WOpen("label=" || cw_file, "size=" || (cw_col + Cwidth) || "," || height, "posx=" || WAttrib(cw_interface, "posx"), "posy=" || WAttrib(cw_interface, "posy") + cw_yoff) | ExitNotice("Cannot open window") y := 0 every name := !cw_names do { Fg(cw_win, "black") CenterString(cw_win, cw_col / 2, y + (Lheight / 2), name) Fg(cw_win, cw.table[name]) | { Notice("Invalid color: " || cw.table[name], "substituting black") Fg(cw_win, "black") } FillRectangle(cw_win, cw_col, y, Cwidth, Lheight) y +:= Lheight } if \cw_active then expose(cw_win) return end procedure new_cw() if /cw_touched then { # ask if colorway is to be saved first } cw := colorway(table()) win_cw() cw_touched := &null return end procedure save_cw() local output repeat { if SaveDialog(, cw_file) == "Cancel" then fail output := open(dialog_value, "w") | { Notice("Cannot open " || dialog_value || " for writing") next } xencodet(cw, output, "colorway") | ExitNotice("Internal inconsistency: color way is corrupt") close(output) cw_touched := &null return } end procedure save_cw_as() local output, temp repeat { if SaveDialog("Save as:") == "Cancel" then fail if dialog_value == \cw_file then { temp := dialog_value if TextDialog("Overwrite existing file?") == "Cancel" then next dialog_value := temp } output := open(dialog_value, "w") | { Notice("Cannot open " || dialog_value || " for writing") next } xencodet(cw, output, "colorway") | ExitNotice("Internal inconsistency: color way is corrupt") close(output) cw_touched := &null return } end procedure quit() if \cw_touched then { # ask for save if touched } exit() end # Utility procedure to let user pick an image file in the current directory. procedure pick() local plist, ls, input, x plist := filelist("*.cw") | return FailNotice("Pick not supported on this platform") if *plist = 0 then return FailNotice("No files found.") repeat { if SelectDialog("Select color way:", plist, plist[1]) == "Cancel" then fail input := open(dialog_value) | { Notice("Cannot open file") next } x := xdecodet(input, "colorway") | { Notice("File does not contain color way") close(input) next } cw_file := dialog_value cw := x win_cw() expose(cw_interface) close(input) cw_touched := &null return } return end #===<>=== modify using vib; do not remove this marker line procedure ui_atts() return ["size=134,169", "bg=gray-white"] end procedure ui(win, cbk) return vsetup(win, cbk, [":Sizer:::0,0,134,169:",], ["active:Button:regular:1:17,38,49,20:edit",active_cb], ["file:Menu:pull::2,2,36,21:File",file_cb, ["new @N","load @L","pick @P","save @S","save as", "quit @Q"]], ["line:Line:::0,25,200,25:",], ["ways:Menu:pull::40,2,36,21:Ways",way_cb, ["add @A","delete @D"]], ) end #===<>=== end of section maintained by vib