3

I am using popup-tip and popup-menu* from the http://melpa.org/#/popup library in my extension, but I'd like to use something in stock Emacs so that I can remain zero dependencies.

The built in popup-menu (i.e. x-popup-menu) and x-show-tip don't work for me because they are mouse-centric (i.e. they show the popup at the mouse location) but I need point centric (i.e. popup where the point is) because that's where the user's gaze is centered when the popup appears.

fommil
  • 1,750
  • 11
  • 24
  • 2
    One option might be to use a child-frame, see [posframe](https://github.com/tumashu/posframe) which makes it easier to create those. But you could also roll you own using `make-frame` – clemera Oct 26 '19 at 12:02
  • that interesting but that's just trading one extension for another, I am looking for stock only solutions. – fommil Oct 26 '19 at 12:36
  • As I mentioned you can use `make-frame` without using an extension but it requires a bit of work to position and size it correctly. – clemera Oct 26 '19 at 13:41
  • it's very disappointing that emacs doesn't come with this kind of feature out of the box. I'll certainly take a look at how it looks. In terms of customising, I could also look into positioning the stock popup stuff but it's so very difficult to get it right. – fommil Oct 26 '19 at 15:03
  • There is also `tooltip-show` which I totally forgot about. – clemera Oct 26 '19 at 15:06
  • `posframe` is not the same as `popup` in the sense that `posframe` is in GNU ELPA, so it's transparently installable via `package.el` without any extra step necessary from the user. – Stefan Nov 01 '19 at 12:26

2 Answers2

1

The only problem you mention with the "stock" solutions are the positioning. For popup-menu you can provide the position you got from posn-at-point so it appears "at point" instead of "at mouse position". For x-show-tip you need a bit more plumbing to take out the x/y position out of the "posn" and pass it to x-show-tip.

Stefan
  • 26,154
  • 3
  • 46
  • 84
  • What is `popup-frame`? I can't find a function or variable with that name. – jue Oct 28 '19 at 09:19
  • It was what we call "a typo" ;-) Thanks for the heads up. – Stefan Oct 28 '19 at 16:55
  • I'll have a look at trying that! I actually wrote some logic to try and figure out the point but couldn't get it to work. Another small niggle I have with the default look and feel is the appearance of an icon, I'd like it to be *just* the text not a warning sign. – fommil Oct 30 '19 at 09:29
  • @fommil: I have no idea what icon or warning sign you're referring to, I'm afraid. Better make it a separate question. – Stefan Oct 30 '19 at 12:21
  • that's a gtk thing, it looks much better when turned off. – fommil Oct 30 '19 at 13:43
  • the other functional problem with the built in popup is when it disappears. I'd like the behaviour: stay until the user does something. But the only behaviour supported seems to be "stay for X seconds even if the user is typing and you're covering up their point" which is sub optimal :-( – fommil Oct 30 '19 at 13:44
0

I did a little POC that I derived from showtip. It does not depend on any external libs:

(defvar tip-timeout 1)

(defvar tip-parameters
  '((name . "tip")
    (internal-border-width . 2)
    (border-width . 1)
    (no-special-glyphs . t)
    (foreground-color . "white")
    (border-color . "white")
    (background-color . "gray")))

(defun tip-frame-parameter (&rest args)
  (let ((fp (apply #'frame-parameter args)))
    ;; this seems to be a bug on my system
    ;; (frame-parameter nil 'left) => (+ -1)
    (if (numberp fp) fp 0)))

(defun tip-posn-at-point (&optional pos window)
  "Return xy positions of top left corner of glyph a POS.

POS is relative to top left corner of frame containing WINDOW and
defaults to the pos of point in the selected window."
  (let* ((window (or window (selected-window)))
         (xy (posn-x-y (posn-at-point pos window)))
         (edges (window-inside-pixel-edges window)))
    (cons (+ (car xy) (car  edges))
          (+ (cdr xy) (cadr edges)))))

(defun tip (text &optional pos timeout window fg bg)
  "Show TEXT in tooltip.

Show tooltip at buffer position POS which defaults to point in
WINDOW which defaults to the selected one.

Hide tooltip after TIMEOUT which defaults to `tip-timeout'.

FG, BG can be used to override foreground and background color
parameters of `tip-parameters'."
  (let* ((xy (tip-posn-at-point pos window))
         (params tip-parameters)
         (left (+ (tip-frame-parameter nil 'left)
                  (car xy)))
         (top (+ (tip-frame-parameter nil 'top)
                 (cdr xy)
                 (- (+ (if menu-bar-mode 25 0)
                       (if tool-bar-mode 35 0)
                       ;; WHY?
                       40)
                    (if header-line-format
                        (frame-char-height) 0)))))
    (when (stringp fg)
      (setf (alist-get 'foreground-color params) fg)
      (setf (alist-get 'border-color params) fg))
    (when (stringp bg)
      (setf (alist-get 'background-color params) bg))
    (x-show-tip text
                (selected-frame)
                (append params `((left . ,left)
                                 (top . ,top)))
                (or timeout tip-timeout))))
clemera
  • 3,401
  • 13
  • 40
  • White on grey is somewhat unreadable. – jue Oct 28 '19 at 09:31
  • that's interesting, but rolling a minimal alternative to popup is not exactly what I had in mind. I'm looking for something that already exists in stock. – fommil Oct 30 '19 at 13:48