Add button with dynamic menu to emacs's modeline?

1.1k views Asked by At

I'm making my own minor mode for emacs. Now I want to add button to modeline. Click on this button must сause pop-up menu appear. The items of this menu depend on user's actions. I know that there is a way to add a function button to modeline with `minor-mode-alist', but I have no idea how to make dynamic menu.

2

There are 2 answers

0
Bad_ptr On BEST ANSWER

I found more proper way: When you define minor mode, you can specify :lighter param

(define-minor-mode my-minor-mode
  "docstring"
  nil
  :lighter (:eval (format "%s%.5s" "#" "some code if you want dynamic label"))
  ;or just string :lighter "static string"
  :keymap my-minor-mode-map
... ... ... rest of code ....

then you can use easymenu:

(require 'easymenu)

(easy-menu-define my-minor-mode-menu
  my-minor-mode-map
  "Menu for my-minor-mode"
   '("some text"
      "-")) ;separator

; and then add menu items with easy-menu-add-item and remove with easy-menu-remove-item
; it's nothing hard. Read the docs ;)

This menu will be added to global menu-bar and it will pop up if you click on auto added(cause you specified :lighter param) minor-mode button on modeline.

0
Bad_ptr On

Ok. Solution founded.:)
First: define some keymap:

(defconst my-mode-line-map
  (let ((map (make-sparse-keymap)))
    (define-key map [mode-line down-mouse-1]
      (make-sparse-keymap))
    map))

Second: append list with propertized string to modeline:

(setq global-mode-string 
  (append global-mode-string 
    (list
      (propertize string-name
        'local-map my-mode-line-map
        'mouse-face 'mode-line-highlight))))

Third: Now you can add items with

 (define-key my-mode-line-map 
   (vconcat [mode-line down-mouse-1]
     (list some_generated_id_for_future_use))
   (cons name function))

...and remove with

 (define-key my-mode-line-map 
   (vconcat [mode-line down-mouse-1] 
     (list id_of_button_that_u_gave_when_add))
   nil)