;;;; ;;;; Listboxes bindings and procs ;;;; ;;;; Copyright © 1993-1999 Erick Gallesio - I3S-CNRS/ESSI <eg@unice.fr> ;;;; ;;;; Permission to use, copy, modify, distribute,and license this ;;;; software and its documentation for any purpose is hereby granted, ;;;; provided that existing copyright notices are retained in all ;;;; copies and that this notice is included verbatim in any ;;;; distributions. No written agreement, license, or royalty fee is ;;;; required for any of the authorized uses. ;;;; This software is provided ``AS IS'' without express or implied ;;;; warranty. ;;;; ;;;; This software is a derivative work of other copyrighted softwares; the ;;;; copyright notices of these softwares are placed in the file COPYRIGHTS ;;;; ;;;; ;;;; Author: Erick Gallesio [eg@unice.fr] ;;;; Creation date: 17-May-1993 12:35 ;;;; Last file update: 3-Sep-1999 19:52 (eg) ;;;; (select-module Tk) ;; ;; Global variables used in this file ;; (define tk::listbox-selection '()) (define tk::listbox-prev 0) ;; ---------------------------------------------------------------------- ;; Class bindings for listbox widgets. ;; ---------------------------------------------------------------------- (define-binding "Listbox" "<1>" (|W| x y) ; Note: the check for existence of %W below is because this binding ; is sometimes invoked after a window has been deleted (e.g. because ; there is a double-click binding on the widget that deletes it). Users ; can put "break"s in their bindings to avoid the error, but this check ; makes that unnecessary. (when (winfo 'exists |W|) (Tk:listbox-begin-select |W| (|W| 'index (format #f "@~A,~A" x y))))) (define-binding "Listbox" "<Double-1>" ;; Ignore double clicks so that users can define their own behaviors. ;; Among other things, this prevents errors if the user deletes the ;; listbox on a double click. (lambda () #f)) (define-binding "Listbox" "<B1-Motion>" (|W| x y) (set! tk::x x) (set! tk::y y) (Tk:listbox-motion |W| (|W| 'index (format #f "@~A,~A" x y)))) (define-binding "Listbox" "<ButtonRelease-1>" (|W| x y) (Tk:cancel-repeat) (|W| 'activate (format #f "@~A,~A" x y))) (define-binding "Listbox" "<Shift-1>" (|W| x y) (Tk:listbox-begin-extend |W| (|W| 'index (format #f "@~A,~A" x y)))) (define-binding "Listbox" "<Control-1>" (|W| x y) (Tk:listbox-begin-toggle |W| (|W| 'index (format #f "@~A,~A" x y)))) (define-binding "Listbox" "<B1-Leave>" (|W| x y) (set! tk::x x) (set! tk::y y) (Tk:listbox-auto-scan |W|)) (define-binding "Listbox" "<B1-Enter>" () (Tk:cancel-repeat)) (define-binding "Listbox" "<Up>" (|W|) (Tk:listbox-up-down |W| -1)) (define-binding "Listbox" "<Shift-Up>" (|W|) (Tk:listbox-extend-up-down |W| -1)) (define-binding "Listbox" "<Down>" (|W|) (Tk:listbox-up-down |W| 1)) (define-binding "Listbox" "<Shift-Down>" (|W|) (Tk:listbox-extend-up-down |W| 1)) (define-binding "Listbox" "<Left>" (|W|) (|W| 'xview 'scroll -1 'units)) (define-binding "Listbox" "<Control-Left>" (|W|) (|W| 'xview 'scroll -1 'pages)) (define-binding "Listbox" "<Right>" (|W|) (|W| 'xview 'scroll 1 'units)) (define-binding "Listbox" "<Control-Right>" (|W|) (|W| 'xview 'scroll 1 'pages)) (define-binding "Listbox" "<Prior>" (|W|) (|W| 'yview 'scroll -1 'pages)) (define-binding "Listbox" "<Next>" (|W|) (|W| 'yview 'scroll 1 'pages)) (define-binding "Listbox" "<Control-Prior>" (|W|) (|W| 'xview 'scroll -1 'pages)) (define-binding "Listbox" "<Control-Next>" (|W|) (|W| 'xview 'scroll 1 'pages)) (define-binding "Listbox" "<Home>" (|W|) (|W| 'xview 'moveto 0)) (define-binding "Listbox" "<End>" (|W|) (|W| 'xview 'moveto 1)) (define-binding "Listbox" "<Control-Home>" (|W|) (|W| 'activate 0) (|W| 'see 0) (|W| 'selection 'clear 0 'end) (|W| 'selection 'set 0)) (define-binding "Listbox" "<Shift-Control-Home>" (|W|) (Tk:listbox-data-extend |W| 0)) (define-binding "Listbox" "<Control-End>" (|W|) (|W| 'activate 'end) (|W| 'see 'end) (|W| 'selection 'clear 0 'end) (|W| 'selection 'set 'end)) (define-binding "Listbox" "<Shift-Control-End>" (|W|) (Tk:listbox-data-extend |W| (|W| 'index 'end))) (define-binding "Listbox" "<<Copy>>" (|W|) (when (equal? (selection 'own :displayof |W|) |W|) (clipboard 'clear :displayof |W|) (clipboard 'append :displayof |W| (selection 'get :displayof |W|)))) (define-binding "Listbox" "<space>" (|W|) (Tk:listbox-begin-select |W| (|W| 'index 'active))) (define-binding "Listbox" "<Select>" (|W|) (Tk:listbox-begin-select |W| (|W| 'index 'active))) (define-binding "Listbox" "<Control-Shift-space>" (|W|) (Tk:listbox-begin-extend |W| (|W| 'index 'active))) (define-binding "Listbox" "<Shift-Select>" (|W|) (Tk:listbox-begin-extend |W| (|W| 'index 'active))) (define-binding "Listbox" "<Escape>" (|W|) (Tk:listbox-cancel |W|)) (define-binding "Listbox" "<Control-slash>" (|W|) (Tk:listbox-select-all |W|)) (define-binding "Listbox" "<Control-backslash>" (|W|) (unless (equal? (tk-get |W| :selectmode) "browse")) (|W| 'selection 'clear 0 'end)) ;; Additional Tk bindings that aren't part of the Motif look and feel: (define-binding "Listbox" "<Shift-2>" (|W| x y) (|W| 'scan 'mark x y)) (define-binding "Listbox" "<B2-Motion>" (|W| x y) (|W| 'scan 'dragto x y)) ;; Tk:listbox-begin-select -- ;; ;; This procedure is typically invoked on button-1 presses. It begins ;; the process of making a selection in the listbox. Its exact behavior ;; depends on the selection mode currently in effect for the listbox; ;; see the Motif documentation for details. ;; ;; w - The listbox widget. ;; el - The element for the selection operation (typically the ;; one under the pointer). Must be in numerical form. (define (Tk:listbox-begin-select w el) (if (equal? (tk-get w :selectmode) "multiple") (if (w 'selection 'includes el) (w 'selection 'clear el) (w 'selection 'set el)) (begin (w 'selection 'clear 0 'end) (w 'selection 'set el) (w 'selection 'anchor el) (set! tk::listbox-selection '()) (set! tk::listbox-prev el)))) ;; Tk:listbox-Motion -- ;; ;; This procedure is called to process mouse motion events while ;; button 1 is down. It may move or extend the selection, depending ;; on the listbox's selection mode. ;; ;; w - The listbox widget. ;; el - The element under the pointer (must be a number). (define (Tk:listbox-Motion w el) (unless (= el tk::listbox-prev) (let ((anchor (w 'index 'anchor)) (mode (tk-get w :selectmode))) (cond ((string=? mode "browse") (w 'selection 'clear 0 'end) (w 'selection 'set el) (set! tk::listbox-prev el)) ((string=? mode "extended") (let ((i tk::listbox-prev)) (if (w 'selection 'includes 'anchor) (begin (w 'selection 'clear i el) (w 'selection 'set 'anchor el)) (begin (w 'selection 'clear i el) (w 'selection 'clear 'anchor el))) (while (and (< i el) (< i anchor)) (if (member i tk::listbox-selection) (w 'selection 'set i)) (set! i (+ i 1))) (while (and (> i el) (> i anchor)) (if (member i tk::listbox-selection) (w 'selection 'set i)) (set! i (- i 1))) (set! tk::listbox-prev el))))))) ;; Tk:listbox-BeginExtend -- ;; ;; This procedure is typically invoked on shift-button-1 presses. It ;; begins the process of extending a selection in the listbox. Its ;; exact behavior depends on the selection mode currently in effect ;; for the listbox; see the Motif documentation for details. ;; ;; w - The listbox widget. ;; el - The element for the selection operation (typically the ;; one under the pointer). Must be in numerical form. (define (Tk:listbox-begin-extend w el) (when (equal? (tk-get w :selectmode) "extended") (if (w 'selection 'includes 'anchor) (Tk:listbox-motion w el) ;; No selection yet; simulate the begin-select operation (Tk:listbox-begin-select w el)))) ;; Tk:listbox-begin-toggle -- ;; ;; This procedure is typically invoked on control-button-1 presses. It ;; begins the process of toggling a selection in the listbox. Its ;; exact behavior depends on the selection mode currently in effect ;; for the listbox; see the Motif documentation for details. ;; ;; w - The listbox widget. ;; el - The element for the selection operation (typically the ;; one under the pointer). Must be in numerical form. (define (Tk:listbox-begin-toggle w el) (when (equal? (tk-get w :selectmode) "extended") (set! tk::listbox-selection (w 'curselection)) (set! tk::listbox-prev el) (w 'selection 'anchor el) (if (w 'selection 'includes el) (w 'selection 'clear el) (w 'selection 'set el)))) ;; Tk:listbox-auto-scan -- ;; This procedure is invoked when the mouse leaves an entry window ;; with button 1 down. It scrolls the window up, down, left, or ;; right, depending on where the mouse left the window, and reschedules ;; itself as an "after" command so that the window continues to 'scroll until ;; the mouse moves back into the window or the mouse button is released. ;; ;; Arguments: ;; w - The entry window. (define (Tk:listbox-auto-scan w) (when (winfo 'exists w) (let* ((x tk::x) (y tk::y) (scan (lambda () (Tk:listbox-motion w (w 'index (format #f "@~A,~A" x y))) (set! tk::after-id (after 50 (lambda () (Tk:listbox-auto-scan w))))))) (cond ((>= y (winfo 'height w)) (w 'yview 'scroll +1 'units) (scan)) ((< y 0) (w 'yview 'scroll -1 'units) (scan)) ((>= x (winfo 'width w)) (w 'xview 'scroll +2 'units) (scan)) ((< x 0) (w 'xview 'scroll -2 'units) (scan)))))) ;; Tk:listbox-up-down -- ;; ;; Moves the location cursor (active element) up or down by one element, ;; and changes the selection if we're in browse or extended selection ;; mode. ;; ;; w - The listbox widget. ;; amount - +1 to move down one item, -1 to move back one item. (define (Tk:listbox-up-down w amount) (let ((mode (tk-get w :selectmode))) (w 'activate (+ (w 'index 'active) amount)) (w 'see 'active) (cond ((string=? mode "browse") (w 'selection 'clear 0 'end) (w 'selection 'set 'active)) ((string=? mode "extended") (w 'selection 'clear 0 'end) (w 'selection 'set 'active) (w 'selection 'anchor 'active) (set! tk::listbox-prev (w 'index 'active)) (set! tk::listbox-selection '()))))) ;; Tk:listbox-extend-up-down -- ;; ;; Does nothing unless we're in extended selection mode; in this ;; case it moves the location cursor (active element) up or down by ;; one element, and extends the selection to that point. ;; ;; w - The listbox widget. ;; amount - +1 to move down one item, -1 to move back one item. (define (Tk:listbox-extend-up-down w amount) (when (equal? (tk-get w :selectmode) "extended") (w 'activate (+ (w 'index 'active) amount)) (w 'see 'active) (Tk:listbox-motion w (w 'index 'active)))) ;; Tk:listbox-data-extend ;; ;; This procedure is called for key-presses such as Shift-KEndData. ;; If the selection mode isn't multiple or extend then it does nothing. ;; Otherwise it moves the active element to el and, if we're in ;; extended mode, extends the selection to that point. ;; ;; w - The listbox widget. ;; el - An integer element number. (define (Tk:listbox-data-extend w el) (let ((mode (tk-get w :selectmode))) (cond ((string=? mode "extended") (w 'activate el) (w 'see el) (if (w 'selection 'includes 'anchor) (Tk:listbox-motion w el))) ((string=? mode "multiple") (w 'activate el) (w 'see el))))) ;; Tk:listbox-cancel ;; ;; This procedure is invoked to cancel an extended selection in ;; progress. If there is an extended selection in progress, it ;; restores all of the items between the active one and the anchor ;; to their previous selection state. ;; ;; w - The listbox widget. (define (Tk:listbox-cancel w) (when (equal? (tk-get w :selectmode) "extended") (let ((first (w 'index 'anchor)) (last tk::listbox-prev)) (when (> first last) (let ((tmp first)) (set! first last) (set! last tmp))) (w 'selection 'clear first last) (while (<= first last) (if (member first tk::listbox-selection) (w 'selection 'set first)) (set! first (+ first 1)))))) ;; Tk:listbox-select-all ;; ;; This procedure is invoked to handle the "select all" operation. ;; For single and browse mode, it just selects the active element. ;; Otherwise it selects everything in the widget. ;; ;; w - The listbox widget. (define (Tk:listbox-select-all w) (let ((mode (tk-get w :selectmode))) (if (or (equal? mode "single") (equal? mode "browse")) (begin (w 'selection 'clear 0 'end) (w 'selection 'set 'active)) (w 'selection 'set 0 'end))))