stk/Lib/scrollbar.stk

360 lines
12 KiB
Plaintext

;;;;
;;;; Scrollbars 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:54 (eg)
;;;;
(select-module Tk)
(let ()
(define tk::init-pos "")
(define tk::init-values '())
;; Standard Motif bindings:
(define-binding "Scrollbar" "<Enter>" (|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" "<Motion>" (|W| x y)
(|W| 'activate (|W| 'identify x y)))
(define-binding "Scrollbar" "<Leave>" (|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" "<B1-Motion>" (|W| x y)
(Tk:scroll-drag |W| x y))
(define-binding "Scrollbar" "<B1-B2-Motion>" (|W| x y)
(Tk:scroll-drag |W| x y))
(define-binding "Scrollbar" "<ButtonRelease-1>" (|W| x y)
(Tk:scroll-button-up |W| x y))
(define-binding "Scrollbar" "<B1-Leave>" ()
;; Prevents <Leave> binding from being invoked.
'nop)
(define-binding "Scrollbar" "<B1-Enter>" ()
;; Prevents <Enter> binding from being invoked.
'nop)
(define-binding "Scrollbar" "<2>" (|W| x y)
(Tk:scroll-button-2-down |W| x y))
(define-binding "Scrollbar" "<B1-2>" ()
; Do nothing, since button 1 is already down.
'nop)
(define-binding "Scrollbar" "<B2-1>" (|W| x y)
; Do nothing, since button 2 is already down.
'nop)
(define-binding "Scrollbar" "<B2-Motion>" (|W| x y)
(Tk:scroll-drag |W| x y))
(define-binding "Scrollbar" "<ButtonRelease-2>" (|W| x y)
(Tk:scroll-button-up |W| x y))
(define-binding "Scrollbar" "<B1-ButtonRelease-2>" ()
;Do nothing: B1 release will handle it.
'nop)
(define-binding "Scrollbar" "<B2-ButtonRelease-1>" ()
;Do nothing: B1 release will handle it.
'nop)
(define-binding "Scrollbar" "<B2-Leave>" ()
;; Prevents <Leave> binding from being invoked.
'nop)
(define-binding "Scrollbar" "<B2-Enter>" ()
;; Prevents <Enter> binding from being invoked.
'nop)
(define-binding "Scrollbar" "<Control-1>" (|W| x y)
(Tk:scroll-top-bottom |W| x y))
(define-binding "Scrollbar" "<Control-2>" (|W| x y)
(Tk:scroll-top-bottom |W| x y))
(define-binding "Scrollbar" "<Up>" (|W|) (Tk:scroll-by-units |W| 'v -1))
(define-binding "Scrollbar" "<Down>" (|W|) (Tk:scroll-by-units |W| 'v +1))
(define-binding "Scrollbar" "<Control-Up>" (|W|) (Tk:scroll-by-pages |W| 'v -1))
(define-binding "Scrollbar" "<Control-Down>" (|W|) (Tk:scroll-by-pages |W| 'v +1))
(define-binding "Scrollbar" "<Left>" (|W|) (Tk:scroll-by-units |W| 'h -1))
(define-binding "Scrollbar" "<Right>" (|W|) (Tk:scroll-by-units |W| 'h +1))
(define-binding "Scrollbar" "<Control-Left>" (|W|) (Tk:scroll-by-pages |W| 'h -1))
(define-binding "Scrollbar" "<Control-Right>" (|W|) (Tk:scroll-by-pages |W| 'hd +1))
(define-binding "Scrollbar" "<Prior>" (|W|) (Tk:scroll-by-pages |W| 'hv -1))
(define-binding "Scrollbar" "<Next>" (|W|) (Tk:scroll-by-pages |W| 'hv +1))
(define-binding "Scrollbar" "<Home>" (|W|)
(Tk:scroll-to-pos |W| 0))
(define-binding "Scrollbar" "<End>" (|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)))))
)