gnu-emacs-sources
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

;;; tooltip-at-point.el --- library for displaying tooltips at (point)


From: Kevin A. Burton (burtonator)
Subject: ;;; tooltip-at-point.el --- library for displaying tooltips at (point)
Date: 18 Dec 2002 16:14:00 -0800
User-agent: Gnus/5.0808 (Gnus v5.8.8) Emacs/21.2.90

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


first release... see commentary

;;; tooltip-at-point.el --- library for displaying tooltips at (point)

;; $Id: tooltip-at-point.el,v 1.12 2002/12/19 04:36:45 burton Exp $

;; Copyright (C) 2000-2003 Free Software Foundation, Inc.
;; Copyright (C) 2000-2003 Kevin A. Burton (address@hidden)

;; Author: Kevin A. Burton (address@hidden)
;; Maintainer: Kevin A. Burton (address@hidden)
;; Location: http://relativity.yi.org
;; Keywords: 
;; Version: 1.0.0

;; This file is [not yet] part of GNU Emacs.

;; This program is free software; you can redistribute it and/or modify it under
;; the terms of the GNU General Public License as published by the Free Software
;; Foundation; either version 2 of the License, or any later version.
;;
;; This program is distributed in the hope that it will be useful, but WITHOUT
;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
;; FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
;; details.
;;
;; You should have received a copy of the GNU General Public License along with
;; this program; if not, write to the Free Software Foundation, Inc., 59 Temple
;; Place - Suite 330, Boston, MA 02111-1307, USA.

;;; Commentary:
;;
;; This package provides the ability to bring up a tooltip at the current point.
;;
;; For the last year or so I have been frustrated with the fact that Emacs
;; doesn't provide floating windows.
;;
;; I think there is a lot of functionality that Emacs is missing because it
;; can't do complex "quick" user interfaces.

;; This prohibits a lot of functionality. For example I developed a library
;; called irepeat that takes an associated list of data (function calls, method
;; pointers, etc) and quickly sorts through the list as you type. If you have
;; bash it is very much like C-r but supports any data set.

;; The problem is that irepeat is limited to using the minibuffer which isn't
;; really a lot of information for the user. Ideally I would bring up a
;; lightweight buffer right above the minibuffer to show other options available
;; to the user.

;; This was accomplished with the tooltip support available within Emacs 21. The
;; interesting thing about this is that tooltips are implemented with standard
;; Emacs windows and buffers so I can use standard font properties and font-lock
;; code.

;; This could yield some very interesting functionality. I am specifically
;; thinking of eldoc style just-in-time method and function completion and quick
;; documentation lookup.

;; Most modern IDEs (Visual Studio, KDE Studio, Borland JBuilder, IBM Visual
;; Age, etc) support this functionality and there is no reason that Emacs should
;; be left behind.

;; The is only one area that Emacs needs improvement to support this type of
;; API. We need the ability to determine the X and Y (top and left) coords for
;; (point) on the screen (the current active cursor).

;; I have looked through all the Emacs code at length and have found NO way to
;; accomplish through lisp. The only way to do this is through C which 
prohibits a
;; lot of innovation by developers.

;; I have tried looking at the Emacs event system but keyboard events to not
;; generate cursor position (only mouse events). I have also tried to pursue 
using
;; a hack to move the mouse to the current cursor and back but this also is
;; impossible for a number of reasons.

;; It is also impossible to calculate the cursor position based on frame width,
;; position and window sizes due to the fact that Emacs can use dynamic fonts on
;; Emacs 21.

;; Can the GNU Emacs developers either:

;; # provide an API to determine the x and y coords of the current active 
cursor (point)

;; # provide a x-show-top-at-point function that provided the exact same 
functionality.

;; Either one of these should be fairly trivial to implement but would deliver a
;; lot of compelling functionality for Emacs users.

;; This package provides an initial tooltip-at-point implementation by
;; "cheating" by temporarily moving the mouse without the user noticing.  We are
;; then able to obtain the top and left coords of the point and we then bring up
;; our tooltip at that point.

;; It is hoped that this package will motivate for Emacs developers to
;; incorporate this functionality into the core.

;; I documented my work on tooltips at to following URLs.
;;
;; 
http://www.peerfear.org/rss/permalink/2002/11/22/1038017513-Emacs_tooltipatpoint_Implementation.shtml
;;
;; 
http://www.peerfear.org/rss/permalink/2002/11/22/1038007519-Emacs_Needs_Floating_Windows.shtml

;; NOTE: If you enjoy this software, please consider a donation to the EFF
;; (http://www.eff.org)

;;; TODO:
;;
;; - Compute offsets based on the current face width and height and use those.
;; If we used fix values they might break on some machines that are using
;; dynamic fonts in some buffers.
;;
;; - is it possible to scroll the tooltip if it is too long?  We are going to
;; have to do some serious hacking to get this to work.  It would be really nice
;; though.
;;
;; - When we have a lot of lisp loaded the latency for tooltip creation is much
;; higher.  Check into temp removing some hooks.
;;
;; - if the tooltip is in the bottom of a window we delete all windows and then
;; put it back.

;;; Code:

;;we need to always use the original functions and not ECB advised functions
(require 'ecb) 

(require 'jde-complete-tooltip)
(require 'tooltip-at-point-jde)
(require 'tooltip-at-point-elisp)

(defgroup tooltip-at-point nil
  "Tooltip at point options.")

(defcustom tooltip-at-point-x-offset 35
  "X offset to use for point tooltips."
  :group 'tooltip-at-point
  :type 'integer)

(defcustom tooltip-at-point-y-offset -10
  "Y offset to use for point tooltips."
  :group 'tooltip-at-point
  :type 'integer)

(defcustom tooltip-at-point-timeout 200
  "Timeout for tooltips"
  :group 'tooltip-at-point
  :type 'integer)

(defvar tooltip-at-point-activated nil
  "True if a tooltip is up that was generated from tooltip-at-point")

(defvar tooltip-at-point-activated-time 0
  "Time the last tooltip was activated.")

;;FIXME: I think we should default to using the frames background and
;;foreground.  This way we can still have decent UIs based on fonts.
(defface tooltip-at-point '((t (:foreground "black" :background "lightyellow")))
  "Face for tooltips raised at the current point."
  :group 'tooltip-at-point)

(defun tooltip-at-point--x-max-tooltip-size()
  "Get the max tooltip size that we should be using."

  ;; determine this automatically in the future.
  
  (cons 120 80))

(defun tooltip-at-point(content)
  "Show a tooltip at the given point with the given content represented as a
  string.  See `x-show-tip'."
  (interactive
   (list "hello tooltip-at-point world"))

  ;;tooltip mode needs to be on for mouse tracking so that tips can be disabled
  (tooltip-mode 1)

  ;;(recenter 2)

  (let((mouse-position nil)
       (point-position nil)
       (tip-position nil)
       (left 0)
       (top 0)
       (window-edges nil)
       (ecb-activate-adviced-functions nil))

    (save-window-excursion

      ;;cache the current mouse position.
      (setq mouse-position (mouse-position))

      ;;set the position of the point.
      (setq point-position (mouse-avoidance-point-position))

      (set-mouse-position (car point-position)
                          (car (cdr point-position))
                          (cdr (cdr point-position)))

      (setq tip-position (cdr (mouse-pixel-position)))
            
      ;;we now have the point position cached at tip-position
      
      ;;restore the mouse position

      (let((mouse-x 0)
           (mouse-y 0))

        ;;this is a trick.. if the mouse is off of screen the mouse-position
        ;;will contain 0... we actually want it to do this so that we don't keep
        ;;the mouse over the current (point) which would confuse the user.
        
        (when (and (car (cdr mouse-position))
                   (cdr (cdr mouse-position)))

          (setq mouse-x (car (cdr mouse-position)))
          (setq mouse-y (cdr (cdr mouse-position))))

        (set-mouse-position (car mouse-position) mouse-x mouse-y))
      
      ;;compute the left and top coords
      
      (setq window-edges (window-edges))
      
      (setq left (+ (car tip-position)
                    (frame-parameter (selected-frame) 'left)
                    tooltip-at-point-x-offset))
      
      (setq top (+ (cdr tip-position)
                   (frame-parameter (selected-frame) 'top)
                   (nth 3 window-edges)
                   tooltip-at-point-y-offset)))
      
      ;;now display the tooltip at the tip-position

     (let((tooltip-use-echo-area nil)
           (tooltip-delay 0)
           (tooltip-short-delay 0)
           (tooltip-recent-seconds 0)
           (x-max-tooltip-size (tooltip-at-point--x-max-tooltip-size)))

       (setq tooltip-at-point-activated t)
       (setq tooltip-at-point-activated-time (float-time))
       
       (x-show-tip content
                    (selected-frame)
                    (list (cons 'left left)
                          (cons 'top top)
                          (cons 'foreground-color (face-attribute 
'tooltip-at-point :foreground))
                          (cons 'border-color "lightyellow") ;;we should always
                                                                                
     ;;be lightyellow so that even in dark mode they
                                                                                
     ;;show up
                          (cons 'background-color (face-attribute 
'tooltip-at-point :background)))
                    tooltip-at-point-timeout))))

(defun tooltip-hide (&optional ignored-arg)
  "Hide a tooltip, if one is displayed.
Value is non-nil if tooltip was open."
  (interactive)

  ;;FIXME: but we can go ahead and break if it is a keyboard event.
  ;;never hide if < X milliseconds
  (if (and tooltip-at-point-activated
           (> (- (float-time) tooltip-at-point-activated-time) 1))
      (progn

        (tooltip-hide--impl))
    (if (null tooltip-at-point-activated)
        (progn
          
          (tooltip-hide--impl)))))

(defun tooltip-at-point--mouse-event-p(event)
  "Return true if this was a mouse event."

  (listp event))

(defun tooltip-hide--impl(&optional ignored-arg)
  "Impl of tooltip hiding..."
  
  (tooltip-cancel-delayed-tip)

  (when (x-hide-tip)

    (setq tooltip-hide-time (float-time))
    (setq tooltip-at-point-activated nil)))

(provide 'tooltip-at-point)

;;; tooltip-at-point.el ends here?

- -- 
Kevin A. Burton ( address@hidden, address@hidden, address@hidden )
             Location - San Francisco, CA, Cell - 415.595.9965
        Jabber - address@hidden,  Web - http://www.peerfear.org/
        GPG fingerprint: 4D20 40A0 C734 307E C7B4  DCAA 0303 3AC5 BD9D 7C4D
         IRC - openprojects.net #infoanarchy | #p2p-hackers | #reptile

National borders aren't even speed bumps on the information superhighway.

- --Tim May

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.7 (GNU/Linux)
Comment: Get my public key at: http://relativity.yi.org/pgpkey.txt

iD8DBQE+AQ9IAwM6xb2dfE0RApZkAJ99YN0HR3BsO4/wVHuPBa4OY3ll0wCdHC5m
ZJf2Tcsc+uaHANZi+nXhkw4=
=z6n6
-----END PGP SIGNATURE-----



reply via email to

[Prev in Thread] Current Thread [Next in Thread]