Вопрос
Я хотел бы создать пользовательский интерфейс в виде всплывающего меню , всплывающего меню, аналогичного используемому в Magit .
особенности
Определение всплывающих окон
Всплывающее окно в контексте этого вопроса означает небольшое временное окно, которое содержит коллекцию пунктов меню, чтобы пользователь мог выбрать один и только один из этих элементов.
Положение на экране
Допускается показ всплывающего окна в любой части экрана, но желательно, чтобы оно было достаточно очевидным, и поэтому оно должно отображаться рядом с текущим активным окном.
Содержимое Popup Buffer
Элементы должны отображаться в виде красивой таблицы. Pretty - контекст вопроса означает визуально привлекательный, этого эффекта легче всего достичь, поместив пункты меню в прямые строки, см.,
complete--insert-string
Например. Этот параграф служит для дополнительного разъяснения, вы можете сделать это по-своему, это не сделает ваш ответ неверным.
Выбор пункта меню
Ожидается, что выбор будет выполнен одним нажатием клавиши или, возможно, мышью (хотя это не так важно, поэтому ответы, содержащие предложения, которые не поддерживают мышь, являются законными). Если вы предлагаете решение, которое поддерживает мышь, обратите внимание, что пользователь должен иметь возможность выбирать пункт меню интуитивно понятным способом, то есть, щелкая левой кнопкой мыши по желаемому выбору.
NB мышь можно использовать по-разному, и приветствуются альтернативные способы указания выбора.
Устранение Popup
Как только пользователь выбрал пункт меню способом, описанным выше, буфер и, следовательно, его окно должны быть исключены из вида, а также уничтожены. Окно, которое было активным до вызова всплывающего меню, должно снова получить фокус (то есть стать активным).
Возвращаемое значение и аргументы
Предпочтительно, это следствие действий должно привести к возвращению объекта Lisp. Объект Лиспа может быть:
nil
- это означает, что пользователь отменил всплывающее меню, нажав C-gили каким-либо другим способом †.string
- строка (разрешено использовать символ) должна указыватьstring-equal
на одну из строк, представленных во всплывающем меню, как набор фактических элементов.
Альтернативные способы сообщить остальной программе выбор пользователя или, возможно, его отсутствие, являются приемлемыми. Однако, если неясно, как еще это можно сделать, я прошу всех ответчиков импровизировать и не просить меня прояснить этот аспект.
Это все для возвращаемого значения. Что касается входных параметров, они должны по крайней мере включать коллекцию строк, которые представляют возможные варианты выбора (то есть пункты меню).
Приемлемые ответы
Ожидаемый ответ может иметь следующие формы:
Достаточный фрагмент кода, который позволяет образованному читателю написать функцию, подобную описанной выше; это не ожидается или необходимо писать всю рабочую функцию. Однако, чтобы избежать неопределенности (можно ли пропустить значительную часть кода?), Я должен отметить, что недостающие части фрагмента должны быть описаны в текстовом компоненте ответа.
Ссылка на существующую библиотеку, которая реализует аналогичные функции. Чтобы избежать неопределенности, я должен отметить, что подобное в нашем случае означает, что библиотека может использоваться для создания всплывающего окна (см. Определение выше), которое имеет как минимум 2 или 3 функции, описанные выше. Если предлагаемая библиотека отличается от точки, в которой ранее указанное условие не может быть выполнено, каждый такой случай будет оцениваться независимо и всегда будет поддерживаться, если OP сочтет это полезным.
Описание встроенных функций Emacs или сторонних, которые могут быть использованы для реализации любой функции, описанной в разделе «Функции», см. Выше. Чтобы избежать неопределенности, пожалуйста, четко укажите, как ваш ответ может быть полезен для будущих читателей, которые хотят реализовать всплывающее , всплывающее меню, подобное тому, которое используется в Magit .
† Альтернативные способы отмены всплывающего меню могут включать следующее (но не ограничиваясь этим):
щелкнув за пределами окна всплывающего меню;
уничтожение буфера, содержащего всплывающее окно, без выбора.
magit-popup
. Новый пакет называетсяtransient
, и это то, что используется в текущих версияхmagit
. Смотрите magit.vc/manual/transient для документации.Гидры довольно просто написать:
Hydra - это клавиатурно-ориентированный интерфейс, и в своей базовой форме он не сложнее, чем
easy-menu-define
(встроенный). И это вполне расширяемо, если вы хотите заставить его делать более сложные вещи.Достаточно взглянуть на этот твиттер-интерфейс, нижнее окно - это пользовательский Hydra, написать его не намного сложнее, чем приведенный выше:
Код для этого доступен в вики , а также много других примеров.
источник
После некоторых исследований я нашел идиому, которая может быть использована для создания окна в нижней части (или даже где угодно) текущего активного окна. Это само по себе имеет эффект временного вспомогательного окна:
Вы можете немного поиграть с
action
аргументом,with-current-buffer-window
если вы хотите, чтобы всплывающее окно появлялось в другой части экрана.Функция выхода описана в строке документа
with-current-buffer-window
, ее можно использовать для получения ввода от пользователя. Как предположил @tarsius,read-char-choice
это хороший кандидат для экспериментов.Сам всплывающий буфер может быть сгенерирован так же, как и любой другой буфер. Я все еще думаю о кнопках, потому что пользователь может использовать свою мышь, чтобы выбрать элемент во всплывающем меню, а не только клавиатуру. Однако это требует дополнительных усилий, если вы хотите сделать это хорошо.
Если ваше всплывающее окно нерегулярно и вам оно не понадобится более одного раза, вы можете воспользоваться этим решением. Кроме того, взгляните на
completion--insert-strings
. Я нашел это весьма полезным в качестве примера того, как генерировать красивые строки пунктов меню, вы даже можете использовать его без изменений, если вам не нужно что-то особенное.источник
Вот стороннее решение, использующее Сосульки .
Ваш код всплывает в окне с кандидатами, аккуратно оформленными в виде меню. Как это сделать, смотрите ниже.
Вы ставите перед каждым пунктом меню уникальный символ. Например, a, b, c ... или 1, 2, 3 ... Пользователь нажимает на символ, чтобы выбрать элемент.
Вы связываете несколько переменных вокруг вызова
completing-read
. Вы передаете ему список своих пунктов меню. Вы можете указать один из элементов по умолчанию, выбранный, если пользователь просто нажимаетRET
.Привязки переменных говорят
completing-read
:Вы можете сделать пункты меню настолько необычными, насколько вы хотите (не показано).
mouse-3
всплывающее меню, чтобы сделать что-нибудь с элементомВы также можете создавать действительно меню с множественным выбором , то есть меню, в которых пользователь может выбрать несколько элементов одновременно (выберите подмножество возможных вариантов).
источник
Вам также может быть интересно посмотреть на пакет
makey
. Он предназначен для обеспечения аналогичных функциональных возможностейmagit-popup
, и является ответвлением предшественникаmagit-popup
(magit-key-mode
упомянутого в комментарии), когда он еще не был доступен отдельно отmagit
.Позвольте мне также упомянуть
discover
: это пример того, как использоватьmakey
(а также его смысл). Этот пакет предназначен, чтобы помочь новичкам обнаружить привязки Emacs.Ссылки
makey
иdiscover
его автор.magit-popup
было сделано в его собственной упаковке.источник
Руководство-ключ хорошо работает для меня для всех настроенных префиксов.
источник
На основе ответа @ Drew (Icicles), с изменениями, позволяющими отделить реализацию меню от данных меню, чтобы можно было определить несколько меню, каждое со своим собственным: (content, prompt, default).
При желании в этом случае используется плющ (при его наличии), который обладает более продвинутыми функциями, такими как возможность активировать элементы, оставляя меню открытым.
Общий всплывающее окно.
Пример использования, назначьте некоторые действия клавише f12:
источник