List Box Functions

Function Syntax (LM:ListTop / ListUp / ListDown / ListBottom <idx> <lst>)
Current Version 1.0
Arguments
Symbol Type Description
idx List List of indexes of items to be moved
lst List List in which items reside
Returns
Type Description
List List of new indexes and repositioned items

Program Description

There are many programs which involve providing the ability for the user to reorder a list of items to suit their requirements, such as arranging layouts, layers or blocks.

In my experience, the most intuitive way to approach this situation is through utilisation of a DCL List Box coupled with a set of controls to manipulate items listed therein. Indeed, I followed this approach with my TabSort program, which allows the user to reorder (among other functionalities) the layout tabs in a drawing; and also with my Layer Draw Order program, allowing the user to manipulate the relative draw-order of objects on each layer in a drawing.

To this end, I offer the following set of functions which may be used to manipulate the order of multiple items in a DCL List Box. Each function requires a list of indexes of the items which are to be reordered, and a list of all items to be displayed in the DCL List Box. Following the reordering operation, the functions will each return a list of two elements: the first, a list of the indexes at which the reordered items are now located; and the second, the list of all items following the rearrangement operation.

Examples of how these functions may be utilised are shown below.

List Box Functions

Includes Remove Items subfunction.

Select all
;;------------------=={ ListBox: List Up }==------------------;;
;;                                                            ;;
;;  Moves the items at the specified indexes 'up' a place in  ;;
;;  the supplied list, that is, to a lower index (if possible);;
;;  whilst retaining the order of the selected items.         ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright  2011 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments:                                                ;;
;;  idx - list of indexes of items to be moved to lower index ;;
;;  lst - list in which items reside                          ;;
;;------------------------------------------------------------;;
;;  Returns:  List of new indexes and items following move    ;;
;;------------------------------------------------------------;;

(defun LM:ListUp ( idx lst / f )
  (defun f ( a b c d e )
    (cond
      ( (or (null b) (null c))
        (list (reverse d) (append (reverse e) c))
      )
      ( (= 0 (car b))
        (f (1+ a) (mapcar '1- (cdr b)) (cdr c) (cons a d) (cons (car c) e))
      )
      ( (= 1 (car b))
        (f (1+ a) (mapcar '1- (cdr b)) (cons (car c) (cddr c)) (cons a d) (cons (cadr c) e))
      )
      ( t
        (f (1+ a) (mapcar '1- b) (cdr c) d (cons (car c) e))
      )
    )
  )
  (f 0 idx lst nil nil)
)

;;-----------------=={ ListBox: List Down }==-----------------;;
;;                                                            ;;
;;  Moves the items at the specified indexes 'down' a place   ;;
;;  in the supplied list, that is, to a higher index          ;;
;;  (if possible) whilst retaining the order of the selected  ;;
;;  items.                                                    ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright  2011 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments:                                                ;;
;;  idx - list of indexes of items to be moved to higher index;;
;;  lst - list in which items reside                          ;;
;;------------------------------------------------------------;;
;;  Returns:  List of new indexes and items following move    ;;
;;------------------------------------------------------------;;

(defun LM:ListDown ( idx lst )
  (apply 
   '(lambda ( a b )
      (list
        (reverse (mapcar '(lambda ( x ) (- (length lst) x 1)) a))
        (reverse b)
      )
    )
    (LM:ListUp
      (reverse (mapcar '(lambda ( x ) (- (length lst) x 1)) idx))
      (reverse lst)
    )
  )
)

;;-----------------=={ ListBox: List Top }==------------------;;
;;                                                            ;;
;;  Moves the items at the specified indexes to the 'top' of  ;;
;;  the supplied list, that is, to the lowest index whilst    ;;
;;  preserving the order of the selected items.               ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright  2011 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments:                                                ;;
;;  idx - list of indexes of items to be moved                ;;
;;  lst - list in which items reside                          ;;
;;------------------------------------------------------------;;
;;  Returns:  List of new indexes and items following move    ;;
;;------------------------------------------------------------;;

(defun LM:ListTop ( idx lst )
  (
    (lambda ( j )
      (list (mapcar '(lambda ( x ) (setq j (1+ j))) idx)
        (append
          (mapcar '(lambda ( x ) (nth x lst)) idx) (LM:RemoveItems idx lst)
        )
      )
    )
    -1
  )
)

;;---------------=={ ListBox: List Bottom }==-----------------;;
;;                                                            ;;
;;  Moves the items at the specified indexes to the 'bottom'  ;;
;;  of the supplied list, that is, to the highest index       ;;
;;  whilst preserving the order of the selected items.        ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright  2011 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments:                                                ;;
;;  idx - list of indexes of items to be moved                ;;
;;  lst - list in which items reside                          ;;
;;------------------------------------------------------------;;
;;  Returns:  List of new indexes and items following move    ;;
;;------------------------------------------------------------;;

(defun LM:ListBottom ( idx lst )
  (
    (lambda ( j )
      (list (mapcar '(lambda ( x ) (setq j (1+ j))) idx)
        (append
          (LM:RemoveItems idx lst) (mapcar '(lambda ( x ) (nth x lst)) idx)
        )
      )
    )
    (- (length lst) (length idx) 1)
  )
)

;;--------------------=={ Remove Items }==--------------------;;
;;                                                            ;;
;;  Removes the items at specified indexes from a list        ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright  2011 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments:                                                ;;
;;  items - list of zero-based indexes to remove              ;;
;;  lst   - list from which items are to be removed           ;;
;;------------------------------------------------------------;;
;;  Returns:  List with items removed                         ;;
;;------------------------------------------------------------;;

(defun LM:RemoveItems ( idx lst / j )
  (setq j -1)
  (vl-remove-if '(lambda ( x ) (member (setq j (1+ j)) idx)) lst)
)

Example Function Calls

_$ (setq lst '(0 1 2 3 4 5 6 7 8))
(0 1 2 3 4 5 6 7 8)

_$ (LM:ListUp '(2 4 6) lst)
((1 3 5) (0 2 1 4 3 6 5 7 8))

_$ (LM:ListDown '(2 4 6) lst)
((3 5 7) (0 1 3 2 5 4 7 6 8))

_$ (LM:ListTop '(2 4 6) lst)
((0 1 2) (2 4 6 0 1 3 5 7 8))

_$ (LM:ListBottom '(2 4 6) lst)
((6 7 8) (0 1 3 5 7 8 2 4 6))

Example Test Function

Select all
;;---------------=={ ListBox: Test Function }==---------------;;
;;                                                            ;;
;;  An example program to demonstrate the usage of the        ;;
;;  ListBox functions to manipulate items in a list.          ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright  2011 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;

(defun c:test ( / *error* _listbox _value->list _list->value alist file id tmp value )

  (defun *error* ( msg )
    (if (< 0 id) (unload_dialog id))
    (if (and tmp (findfile tmp)) (vl-file-delete tmp))
    (or (wcmatch (strcase msg) "*BREAK,*CANCEL*,*EXIT*")
        (princ (strcat "\n** Error: " msg " **")))
    (princ)
  )

  (defun _listbox ( key lst )
    (start_list key) (mapcar 'add_list lst) (end_list)
  )
  
  (defun _value->list ( val ) (read (strcat "(" val ")")))

  (defun _list->value ( lst ) (vl-string-trim "()" (vl-princ-to-string lst)))
  
  (cond
    (
      (not
        (and (setq file (open (setq tmp (vl-filename-mktemp nil nil ".dcl")) "w"))
          (progn
            (foreach x
             '(
                "listbox : dialog { label = \"List Box Example\"; spacer;"
                "  : row {"
                "    : list_box { key = \"list\"; width = 35; fixed_width = true; height = 15; fixed_height = true; multiple_select = true; }"
                "    : column { fixed_height = true;"
                "      : button { key = \"top\";    label = \"Top\";    }"
                "      : button { key = \"up\";     label = \"Up\" ;    }"
                "      : button { key = \"down\";   label = \"Down\";   }"
                "      : button { key = \"bottom\"; label = \"Bottom\"; }"
                "    }"
                "  }"
                "  ok_only;"
                "}"
              )
              (write-line x file)
            )
            (setq file (close file)) (< 0 (setq id (load_dialog tmp)))
          )
          (new_dialog "listbox" id)
        )
      )
      (princ "\n--> Error Loading Dialog.")
    )
    (t
      (_listbox "list" (setq alist '("Item 1" "Item 2" "Item 3" "Item 4" "Item 5" "Item 6" "Item 7")))
      (set_tile "list" (setq value "0"))

      (action_tile "list" "(setq value $value)")

      (mapcar
        (function
          (lambda ( key func )
            (action_tile key
              (vl-prin1-to-string
                (list
                 '(lambda ( data )
                    (_listbox "list" (setq alist (cadr data)))
                    (set_tile "list" (setq value (_list->value (car data))))
                  )
                  (list func '(_value->list value) 'alist)
                )
              )
            )
          )
        )
       '("top" "up" "down" "bottom")
       '(LM:ListTop LM:ListUp LM:ListDown LM:ListBottom)
      )
      (start_dialog)
    )
  )
  (if (< 0 id) (unload_dialog id))
  (if (and tmp (findfile tmp)) (vl-file-delete tmp))
  (princ)
)
(vl-load-com) (princ)

Demonstration of Test Function

List Box Functions.gif

textsize

increase · reset · decrease

Designed & Created by Lee Mac © 2010