;;;; ;;;; Scrollbars bindings and procs ;;;; ;;;; Copyright © 1993-1999 Erick Gallesio - I3S-CNRS/ESSI ;;;; ;;;; 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:54 (eg) ;;;; (select-module Tk) (let () (define tk::init-pos "") (define tk::init-values '()) ;; Standard Motif bindings: (define-binding "Scrollbar" "" (|W| x y) (when *tk-strict-motif* (set! tk::active-bg (tk-get |W| :activebackground)) (tk-set! |W| :activebackground (tk-get |W| :background))) (|W| 'activate (|W| 'identify x y))) (define-binding "Scrollbar" "" (|W| x y) (|W| 'activate (|W| 'identify x y))) (define-binding "Scrollbar" "" (|W|) (if *tk-strict-motif* (tk-set! |W| :activebackground tk::active-bg)) (|W| 'activate "")) (define-binding "Scrollbar" "<1>" (|W| x y) (Tk:scroll-button-down |W| x y)) (define-binding "Scrollbar" "" (|W| x y) (Tk:scroll-drag |W| x y)) (define-binding "Scrollbar" "" (|W| x y) (Tk:scroll-drag |W| x y)) (define-binding "Scrollbar" "" (|W| x y) (Tk:scroll-button-up |W| x y)) (define-binding "Scrollbar" "" () ;; Prevents binding from being invoked. 'nop) (define-binding "Scrollbar" "" () ;; Prevents binding from being invoked. 'nop) (define-binding "Scrollbar" "<2>" (|W| x y) (Tk:scroll-button-2-down |W| x y)) (define-binding "Scrollbar" "" () ; Do nothing, since button 1 is already down. 'nop) (define-binding "Scrollbar" "" (|W| x y) ; Do nothing, since button 2 is already down. 'nop) (define-binding "Scrollbar" "" (|W| x y) (Tk:scroll-drag |W| x y)) (define-binding "Scrollbar" "" (|W| x y) (Tk:scroll-button-up |W| x y)) (define-binding "Scrollbar" "" () ;Do nothing: B1 release will handle it. 'nop) (define-binding "Scrollbar" "" () ;Do nothing: B1 release will handle it. 'nop) (define-binding "Scrollbar" "" () ;; Prevents binding from being invoked. 'nop) (define-binding "Scrollbar" "" () ;; Prevents binding from being invoked. 'nop) (define-binding "Scrollbar" "" (|W| x y) (Tk:scroll-top-bottom |W| x y)) (define-binding "Scrollbar" "" (|W| x y) (Tk:scroll-top-bottom |W| x y)) (define-binding "Scrollbar" "" (|W|) (Tk:scroll-by-units |W| 'v -1)) (define-binding "Scrollbar" "" (|W|) (Tk:scroll-by-units |W| 'v +1)) (define-binding "Scrollbar" "" (|W|) (Tk:scroll-by-pages |W| 'v -1)) (define-binding "Scrollbar" "" (|W|) (Tk:scroll-by-pages |W| 'v +1)) (define-binding "Scrollbar" "" (|W|) (Tk:scroll-by-units |W| 'h -1)) (define-binding "Scrollbar" "" (|W|) (Tk:scroll-by-units |W| 'h +1)) (define-binding "Scrollbar" "" (|W|) (Tk:scroll-by-pages |W| 'h -1)) (define-binding "Scrollbar" "" (|W|) (Tk:scroll-by-pages |W| 'hd +1)) (define-binding "Scrollbar" "" (|W|) (Tk:scroll-by-pages |W| 'hv -1)) (define-binding "Scrollbar" "" (|W|) (Tk:scroll-by-pages |W| 'hv +1)) (define-binding "Scrollbar" "" (|W|) (Tk:scroll-to-pos |W| 0)) (define-binding "Scrollbar" "" (|W|) (Tk:scroll-to-pos |W| 1)) ;; Tk:scroll-button-down -- ;; This procedure is invoked when a button is pressed in a scrollbar. ;; It changes the way the scrollbar is displayed and takes actions ;; depending on where the mouse is. ;; ;; w - The scrollbar widget. ;; x, y - Mouse coordinates. (define (Tk:scroll-button-down w x y) (let ((element (w 'identify x y))) (set! tk::relief (tk-get w :activerelief)) (tk-set! w :activerelief "sunken") (if (equal? element "slider") (Tk:scroll-start-drag w x y) (Tk:scroll-select w element "initial")))) ;; Tk:scroll-button-up -- ;; This procedure is invoked when a button is released in a scrollbar. ;; It cancels scans and auto-repeats that were in progress, and restores ;; the way the active element is displayed. ;; ;; w - The scrollbar widget. ;; x, y - Mouse coordinates. (define (Tk:scroll-button-up w x y) (Tk:cancel-repeat) (tk-set! w :activerelief tk::relief) (Tk:scroll-end-drag w x y) (w 'activate (w 'identify x y))) ;; Tk:scroll-select -- ;; This procedure is invoked when a button is pressed over the scrollbar. ;; It invokes one of several scrolling actions depending on where in ;; the scrollbar the button was pressed. ;; ;; w - The scrollbar widget. ;; element - The element of the scrollbar that was selected, such ;; as "arrow1" or "trough2". Shouldn't be "slider". ;; repeat - Whether and how to auto-repeat the action: "noRepeat" ;; means don't auto-repeat, "initial" means this is the ;; first action in an auto-repeat sequence, and "again" ;; means this is the second repetition or later. (define (Tk:scroll-select w element repeat) (when (winfo 'exists w) (let ((cont (lambda () (cond ((string=? repeat "again") (set! tk::after-id (after (tk-get w :repeatinterval) (lambda () (Tk:scroll-select w element "again"))))) ((string=? repeat "initial") (let ((delay (tk-get w :repeatdelay))) (if (> delay 0) (set! tk::after-id (after delay (lambda () (Tk:scroll-select w element "again"))))))))))) (cond ((equal? element "arrow1") (Tk:scroll-by-units w 'hv -1) (cont)) ((equal? element "trough1") (Tk:scroll-by-pages w 'hv -1) (cont)) ((equal? element "trough2") (Tk:scroll-by-pages w 'hv +1) (cont)) ((equal? element "arrow2") (Tk:scroll-by-units w 'hv +1) (cont)))))) ;; Tk:scroll-start-drag -- ;; This procedure is called to initiate a drag of the slider. It just ;; remembers the starting position of the mouse and slider. ;; ;; w - The scrollbar widget. ;; x, y - The mouse position at the start of the drag operation. (define (Tk:scroll-start-drag w x y) (unless (equal? (tk-get w :command) "") (set! tk::press-x x) (set! tk::press-y y) (set! tk::init-values (w 'get)) (let ((iv0 (car tk::init-values))) (if (= (length tk::init-values) 2) (set! tk::init-pos iv0) (if (= iv0 0) (set! tk::init-pos 0.0) (set! tk::init-pos (/ (caddr tk::init-values) (car tk::init-values)))))))) ;; Tk:scroll-drag -- ;; This procedure is called for each mouse motion even when the slider ;; is being dragged. It notifies the associated widget if we're not ;; jump scrolling, and it just updates the scrollbar if we are jump ;; scrolling. ;; ;; w - The scrollbar widget. ;; x, y - The current mouse position. (define (Tk:scroll-drag w x y) (unless (equal? tk::init-pos "") (let ((delta (w 'delta (- x tk::press-x) (- y tk::press-y)))) (if (tk-get w :jump) (if (equal? (length tk::init-values) 2) (w 'set (+ (car tk::init-values) delta) (+ (cadr tk::init-values) delta)) (let ((delta (floor (* delta (car tk::init-values))))) (w 'set (car tk::init-values) (cadr tk::init-values) (+ (caddr tk::init-values) delta) (+ (cadddr tk::init-values) delta)))) (Tk:scroll-to-pos w (+ tk::init-pos delta)))))) ;; Tk:scroll-end-drag -- ;; This procedure is called to end an interactive drag of the slider. ;; It scrolls the window if we're in jump mode, otherwise it does nothing. ;; ;; w - The scrollbar widget. ;; x, y - The mouse position at the end of the drag operation. (define (Tk:scroll-end-drag w x y) (unless (equal? tk::init-pos "") (if (tk-get w :jump) (let ((delta (w 'delta (- x tk::press-x) (- y tk::press-y)))) (Tk:scroll-to-pos w (+ tk::init-pos delta)))) (set! Tk::init-pos ""))) ;; Tk:scroll-by-units -- ;; This procedure tells the scrollbar's associated widget to scroll up ;; or down by a given number of units. It notifies the associated widget ;; in different ways for old and new command syntaxes. ;; ;; w - The scrollbar widget. ;; orient - Which kinds of scrollbars this applies to: "h" for ;; horizontal, "v" for vertical, "hv" for both. ;; amount - How many units to scroll: typically 1 or -1. (define (Tk:scroll-by-units w orient amount) (let ((cmd (tk-get w :command)) (worient (tk-get w :orient))) (unless (equal? cmd "") (when (or (eq? orient 'hv) (and (eq? orient 'h) (string=? worient "horizontal")) (and (eq? orient 'v) (string=? worient "vertical"))) (let ((info (w 'get))) (if (= (length info) 2) (cmd 'scroll amount 'units) (cmd (+ (caddr info) amount)))))))) ;; Tk:scroll-by-pages -- ;; This procedure tells the scrollbar's associated widget to scroll up ;; or down by a given number of screenfuls. It notifies the associated ;; widget in different ways for old and new command syntaxes. ;; ;; Arguments: ;; w - The scrollbar widget. ;; orient - Which kinds of scrollbars this applies to: "h" for ;; horizontal, "v" for vertical, "hv" for both. ;; amount - How many screens to scroll: typically 1 or -1. (define (Tk:scroll-by-pages w orient amount) (let ((cmd (tk-get w :command)) (worient (tk-get w :orient))) (unless (equal? cmd "") (when (or (eq? orient 'hv) (and (eq? orient 'h) (string=? worient "horizontal")) (and (eq? orient 'v) (string=? worient "vertical"))) (let ((info (w 'get))) (if (= (length info) 2) (cmd 'scroll amount 'pages) (cmd (+ (caddr info) (* (cadr info) amount) -1)))))))) ;; Tk:scroll-ToPos -- ;; This procedure tells the scrollbar's associated widget to scroll to ;; a particular location, given by a fraction between 0 and 1. It notifies ;; the associated widget in different ways for old and new command syntaxes. ;; ;; Arguments: ;; w - The scrollbar widget. ;; pos - A fraction between 0 and 1 indicating a desired position ;; in the document. (define (Tk:scroll-to-pos w pos) (let ((cmd (tk-get w :command))) (unless (equal? cmd "") (let ((info (w 'get))) (if (= (length info) 2) (cmd 'moveto pos) (cmd (floor (* (car info) pos)))))))) ;; Tk:scroll-top-bottom ;; Scroll to the top or bottom of the document, depending on the mouse ;; position. ;; ;; w - The scrollbar widget. ;; x, y - Mouse coordinates within the widget. (define (Tk:scroll-top-bottom w x y) (let ((element (w 'identify x y))) (cond ((member element '("arrow1" "trough1")) (Tk:scroll-to-pos w 0)) ((member element '("arrow2" "trough2")) (Tk:scroll-to-pos w 1))) ;; Set tk::relief, since it's needed by Tk:scroll-button-up. (set! tk::relief (tk-get w :activerelief)))) ;; Tk:scroll-button-2-down ;; This procedure is invoked when button 2 is pressed over a scrollbar. ;; If the button is over the trough or slider, it sets the scrollbar to ;; the mouse position and starts a slider drag. Otherwise it just ;; behaves the same as button 1. ;; ;; Arguments: ;; w - The scrollbar widget. ;; x, y - Mouse coordinates within the widget. (define (Tk:scroll-button-2-down w x y) (let ((element (w 'identify x y))) (if (or (equal? element "arrow1") (equal? element "arrow2")) (Tk:scroll-button-down w x y) (begin (Tk:scroll-to-pos w (w 'fraction x y)) (set! tk::relief (tk-get w :activerelief)) ; Need the "update idletasks" below so that the widget calls us ; back to reset the actual scrollbar position before we start the ; slider drag. (update 'idletasks) (tk-set! w :activerelief "sunken") (w 'activate 'slider) (Tk:scroll-start-drag w x y))))) )