Komennot ja valikot¶
Komennot¶
ICommandRegistry on se yksi suppilo, jonka kautta jokainen käyttäjän käynnistettävissä
oleva toiminto kulkee — valikkokohdat, työkalurivin painikkeet, pikanäppäimet ja (myöhemmin)
Python-skriptit.
namespace platform_id { // keys for platformShortcuts
inline constexpr std::string_view kWindows = "windows";
inline constexpr std::string_view kMacOS = "macos";
inline constexpr std::string_view kLinux = "linux";
}
namespace command_scope { // values for CommandDescriptor::scope
inline constexpr std::string_view kApplication = "application";
inline constexpr std::string_view kPluginWindow = "pluginWindow";
}
struct CommandDescriptor {
std::string id; // "helloworld.sayHi"
std::string title; // "Say Hi"
std::string shortcut; // portable default: "Ctrl+Alt+H"
std::string category; // "Hello"
std::string scope; // "" / "application" | "pluginWindow"
std::map<std::string, std::string> platformShortcuts; // optional per-platform
bool requiresEditor = false; // needs an active document
bool requiresWritableEditor = false; // ...and changes its text
};
// Convenience wrappers, so an existing aggregate literal only has to be
// wrapped rather than rewritten:
CommandDescriptor needsEditor(CommandDescriptor); // requiresEditor
CommandDescriptor needsWritableEditor(CommandDescriptor); // + writable
using CommandHandler = std::function<void()>;
class ICommandRegistry {
public:
virtual CommandToken registerCommand(CommandDescriptor, CommandHandler) = 0;
virtual void invoke(std::string_view commandId) = 0;
virtual bool exists(std::string_view commandId) const = 0;
// The user-resolved sequence in effect right now ("" = unbound),
// NOT the declared default. See "User remapping" below.
virtual std::string effectiveShortcut(std::string_view commandId) const = 0;
};
registerCommand palauttaa CommandToken-poletin (RAII). Sen tuhoaminen poistaa komennon,
sen valikkokohdat ja sen pikanäppäimen. Pidä jokaista polettia jäsenenä, jotta koko
liitännäinen purkautuu automaattisesti funktiossa shutdown().
Editorivaatimukset¶
requiresEditor / requiresWritableEditor kertovat isännälle, mitä komento tarvitsee
aktiiviselta asiakirjalta, jotta se voi harmaannuttaa komennon sen sijaan että antaisi
käyttäjän käynnistää jotain, joka ei hiljaisesti tee mitään.
| Lippu | Aseta se, kun komento … | Se harmaantuu … |
|---|---|---|
requiresEditor |
lukee puskuria, valintaa tai kohdistinta tai asettaa merkkejä (Kirjanmerkit, Merkitse, Etsi, Siirry määrittelyyn) | välilehdellä, jolla ei ole lainkaan asiakirjaa — vertailu- tai lokinäkymävälilehdellä, jossa activeDocument() palauttaa arvon 0 |
requiresWritableEditor |
muuttaa tekstiä (Kommentti, Muunna kirjainkoko, Sarake-editori, Lisää sisennystä, Rivit …, Muotoile asiakirja, Nimeä symboli uudelleen) | edellä mainitulla sekä vain luettavassa asiakirjassa: tiedostossa, jota seurataan komennolla tail -f, tai --viewer- tai --readonly-istunnossa |
Kirjoituslippu sisältää toisen, joten kuvaus voi asettaa vain vahvemman niistä. Molempien
oletus on false — »aina käytettävissä«, oikea vastaus komennoille, jotka avaavat ikkunan,
kansion tai paneelin.
Harmaannutus yltää valikkokohtaan, komentopalettiin ja pikanäppäimeen. Se voi vain viedä
käytettävyyden pois: kohta, jonka liitännäisesi itse poisti käytöstä funktiolla
IMenuRegistry::setItemEnabled, pysyy pois käytöstä riippumatta siitä, mikä aktiivinen
asiakirja on.
Kääri kuvaus kutsupaikassa:
using MTE::plugin::needsWritableEditor;
m_toggleComment = ctx.commands().registerCommand(
needsWritableEditor({ "comment.toggle", "Toggle Comment",
"Ctrl+Q", "Comment" }),
[this] { onToggleComment(); });
Pythonissa välität avainsana-argumentit:
@ctx.commands.command(id="wc.upper", title="Upper Case",
requires_writable_editor=True)
def _upper():
...
Alustakohtaiset pikanäppäimet¶
shortcut on yksi siirrettävä näppäinyhdistelmä. Qt kuvaa jo "Ctrl"-muuntonäppäimen
alustan omaan — ⌘ Command macOS:ssä — joten "Ctrl+F" on siellä ⌘F ilman lisätyötä.
Tarvitset enemmän vain silloin, kun tuo automaattinen kuvaus osuisi yhdistelmään, jonka
käyttöjärjestelmä on varannut (esimerkiksi "Ctrl+Q" → ⌘Q = Lopeta macOS:ssä).
Aseta noissa tapauksissa platformShortcuts, avaimena platform_id. Isäntä palauttaa
kohdan, joka vastaa käynnissä olevaa alustaa, tai turvautuu arvoon shortcut, kun alustaa
ei ole mainittu (tai se on kuvattu tyhjäksi merkkijonoksi). Ei #ifdef-lauseita, ei
Qt-tyyppejä — pelkkää dataa — joten sidonta pysyy taustajärjestelmästä riippumattomana ja
uusi alusta on yksi uusi avain:
MTE::plugin::CommandDescriptor desc;
desc.id = "comment.toggle";
desc.title = "Toggle Single Line Comment";
desc.shortcut = "Ctrl+Q"; // Windows / Linux → Ctrl+Q
desc.platformShortcuts = { // macOS → ⌃Q (the portable
{ std::string(MTE::plugin::platform_id::kMacOS), "Meta+Q" } }; // "Meta" = ⌃
desc.category = "Comment";
Varattuja macOS:n ⌘-yhdistelmiä, joita vasten yksittäistä Ctrl+<key>-yhdistelmää
kannattaa tarkistaa: ⌘Q (Lopeta), ⌘W (Sulje), ⌘H (Kätke), ⌘M (Pienennä), ⌘, (Asetukset),
⌘välilyönti (Spotlight). Ctrl+Alt+<key>-yhdistelmän (⌥⌘ macOS:ssä) kohdalla vältä myös
yhdistelmiä ⌥⌘H (Kätke muut), ⌥⌘M (Pienennä kaikki), ⌥⌘D (Dock) ja ⌥⌘Esc (Pakota lopetus).
Kaksi sääntöä lisää pitää pikanäppäimet pois kirjoittamisen tieltä:
- Ei koskaan paljasta
Alt+<letter>siirrettävänä yhdistelmänä. Windowsissa se on valikoiden muistiavainten aluetta, ja macOS:ssä ⌥ + kirjain muodostaa aksenttimerkkejä (⌥U on treema-kuollutnäppäin, ⌥C kirjoittaa ç), joten pikanäppäin nielisi ne — anna tällaiselle komennolle{"macos", "Meta+Alt+<key>"}-ohitus (⌃⌥). Ctrl+Alt+<key>on AltGr+<key>Windowsissa. Kansalliset näppäinasettelut kirjoittavat siellä kirjaimia (puola: ś ł ą ć ę ń ó ź ż €; saksa: @ € µ). Isäntä pitää ne kirjoitettavina — oikean Alt-näppäimen painallus, joka tuottaa tulostettavan merkin, toimitetaan tekstinä, ja vasemman Ctrl+Alt -painallus ajaa komennon — joten tällaiset yhdistelmät ovat sallittuja, mutta suosi kirjaimia, jotka eivät kirjoita mitään yleisillä asetteluilla (B D F G H I J K P R T V W Y), äläkä koskaan käytä yhdistelmääCtrl+Alt+<digit>.
Käyttäjän uudelleenmääritys¶
Ilmoitetut shortcut / platformShortcuts ovat oletuksia. Käyttäjä voi määrittää
jokaisen komennon uudelleen tai poistaa sen määrityksen ytimen pikanäppäinten määrityksessä
(Asetukset ▸ Pikanäppäimet), ja ristiriidat ratkaistaan isännän puolella: saman laajuuden
kaksoiskappaleet eivät koskaan esiinny rinnakkain — häviäjä keskeytetään istunnon ajaksi ja
siitä ilmoitetaan. Mikään tästä ei vaadi liitännäiskoodia tavallisille valikkoon sidotuille
komennoille: isäntä omistaa niiden QAction-olion ja määrittää sen uudelleen lennossa.
scope — komennot liitännäisen omistamissa ikkunoissa¶
Komennot, joiden yhdistelmä sijaitsee liitännäisen omistamassa ohjausobjektissa
(työkaluikkunan työkalurivillä päävalikon sijaan), ilmoittavat arvon
scope = command_scope::kPluginWindow. Isäntä ei silloin koskaan sido yhdistelmää itse; se
vain luettelee komennon määrityksessä ja ratkaisee käyttäjän valinnan. Liitännäinen ottaa
sidonnan käyttöön omissa ohjausobjekteissaan:
- kysy
ctx.commands().effectiveShortcut(id)ohjausobjekteja rakentaessasi ja - tilaa
events::CommandShortcutChanged { commandId, sequence }ja ota sekvenssi uudelleen käyttöön, kun jokin sen tunnisteista muuttuu (""= nyt ilman määritystä).
Ristiriitojen alue on v1:ssä yleinen — pluginWindow-yhdistelmä kieltäytyy törmäämästä
sovellusyhdistelmään. Toimiva esimerkki: Lokianalyysin lokinäkymän työkalurivi
(loganalyzer.logView.nextError F8 / .prevError Shift+F8 / .goToTime Ctrl+G).
Valikot¶
Valikkopolut käyttävät merkkiä / erottimena; isäntä luo välialivalikot tarvittaessa:
class IMenuRegistry {
public:
virtual MenuToken addItem(std::string menuPath, std::string commandId) = 0;
virtual MenuToken addSeparator(std::string menuPath) = 0;
virtual void setItemChecked(TokenId itemToken, bool checked) = 0;
virtual void setItemEnabled(TokenId itemToken, bool enabled) = 0;
};
MenuToken on RAII kuten CommandToken.
Valittavat valikkokohdat¶
Valikkokohta, joka edustaa pysyvää päälle/pois-tilaa, voi kantaa näkyvää valintamerkkiä.
setItemChecked ottaa kohdan TokenId-arvon — käytä poletin tuhoamatonta
id()-käyttäjää (release() luovuttaisi omistajuuden):
m_toggle = ctx.menus().addItem("View/Auto-open preview", "myplugin.toggle");
// Seed the mark from the persisted setting so the menu matches reality
// before the user first opens it:
ctx.menus().setItemChecked(m_toggle.id(),
ctx.settings().getBool("autoOpen", true));
// Inside the command handler, after flipping the setting:
ctx.menus().setItemChecked(m_toggle.id(), nowEnabled);
Ensimmäinen kutsu tekee kohdasta valittavan; seuraavat kutsut vain kääntävät tilan. Tuntematon poletti ei tee hiljaisesti mitään, joten viivästynyt takaisinkutsu, joka laukeaa sammutuksen jälkeen, on vaaraton.
Valikkokohtien harmaannuttaminen¶
Komennon, joka tarvitsee edellytyksen — suljettavan kansion, palautettavan suljetun
välilehden — tulisi harmaannuttaa valikkokohtansa, kun tuo edellytys puuttuu, sen sijaan
että tarjoaisi kohtaa, joka ei hiljaisesti tee mitään. setItemEnabled ottaa kohdan
TokenId-arvon, aivan kuten setItemChecked:
m_closeItem = ctx.menus().addItem("File/Close Folder", "myplugin.closeFolder");
// Nothing to close yet:
ctx.menus().setItemEnabled(m_closeItem.id(), false);
// ... and from every place that changes the state the command needs:
ctx.menus().setItemEnabled(m_closeItem.id(), !folder.empty());
Käytöstä poistettu kohta pysyy näkyvissä muttei ole käynnistettävissä, ei napsautuksella
eikä pikanäppäimellään. Kutsu on idempotentti — saman arvon toistaminen on odotettua, joten
sinun ei tarvitse koskaan muistaa edellistä tilaa — ja tuntematon poletti ei tee
hiljaisesti mitään, kuten yllä. Kohdat alkavat käytössä olevina, joten kohta, joka ei ole
käytettävissä käynnistyksessä, tarvitsee yhden kutsun heti funktion addItem jälkeen.
Valikon sijoitus (plugin.json)¶
Se, missä liitännäisen ylimmän tason valikko sijaitsee, on datavetoista tiedoston
plugin.json menus-taulukon kautta — isäntä ei koskaan kovakoodaa liitännäisvalikkojen
nimiä:
title— ylimmän tason valikko; vastaamenuPath-polkusi ensimmäistä/-erotettua osaa. Anna sille näppäinvihje merkillä&("Lo&g Analyzer") ja käytä samaa kirjoitusasua jokaisessamenuPath-polussa: Windowsissa Alt+kirjain avaa valikon, ja jokainen palkin otsikko tarvitsee oman kirjaimensa, jokaisessa kielessä — valitse vapaa niistä, jotka eivät ole käytössä nimissä Tiedosto, Muokkaa, Haku, Merkistökoodaus, Vertaa, Näytä, Kieli, Liitännäiset, Ikkuna, Tietoja ja Ohje, ja anna jokaisen käännöksen valita omansa. Valikoiden täsmäytys ohittaa merkin.barPriority— vaakasuora sijainti valikkopalkissa (pienempi = kauempana vasemmalla). Ytimen valikoilla on kiinteät, 100:n välein sijoitetut sijainnit: Tiedosto 100, Muokkaa 200, Näytä 300, Kieli 400, Vertaa 500, Ikkuna 600 (Tietoja 1000, aina kaukana oikealla); liitännäiset täyttävät aukot (Haku 250, Merkistökoodaus 350, Lokianalyysi 540, Liitännäiset 570).itemPriority— tämän liitännäisen koko lohkon pystysuora sijainti valikontitlesisällä (pienempi = ylempänä; oletus 1000). Yhden liitännäisen lohkon sisällä kohdat säilyttävät sen järjestyksen, jossa ne lisätään koodissa.
Note
Koska plugin.json upotetaan Qt-liitännäismetatietoina, sen muokkaukset tulevat
voimaan vasta uudelleenkäännöksen jälkeen.