Doki, karty, pasek stanu i motyw¶
Powierzchnie UI, do których wtyczka może kontrybuować poza menu. Wszystkie działają według tego samego wzorca: opisz, czego chcesz, danymi niezależnymi od backendu, przekaż hostowi fabrykę, zatrzymaj zwrócony token RAII.
Panele dokowane¶
ctx.docks() dodaje dokowany panel boczny. Publiczna powierzchnia celowo
przekazuje widżet jako nieprzezroczysty void* — host oparty na Qt rzutuje go
na QWidget*; wtyczka w Pythonie buduje ten sam panel deklaratywnie
(zobacz dokumentację ctx.docks w Pythonie).
class IDockPanel {
public:
void* nativeWidget(); // your QWidget*, host takes ownership
std::string title() const;
};
class IDockPanelFactory {
public:
std::unique_ptr<IDockPanel> create();
};
struct DockPanelDescriptor {
std::string id; // "myplugin.outline"
std::string defaultTitle;
DockArea preferredArea = DockArea::Right; // Left/Right/Top/Bottom
bool initiallyVisible = true; // false = created hidden
};
m_dock = ctx.docks().addPanel(descriptor, std::move(factory));
Host tworzy panel leniwie (przy pierwszym wyświetleniu) i może utworzyć go
ponownie po resecie układu — trzymaj stan panelu poza widżetem albo odbudowuj
go w create(). DockToken usuwa panel przy destrukcji.
Typy kart pierwszej klasy¶
Gdy funkcja zasługuje na własny rodzaj karty (wyniki diffa, widok logów,
podgląd heksadecymalny), a nie bufor tekstowy czy panel boczny, zarejestruj typ
karty przez ctx.documents():
struct DocumentTabTypeDescriptor {
std::string typeId; // "log-view" -- lowercase-with-hyphens
std::string displayName; // localized type name
DefaultPlacement defaultPlacement; // ActiveGroup / NewGroupRight / NewGroupBottom
};
m_type = ctx.documents().registerType(descriptor, std::move(factory));
ctx.documents().openTab("log-view", {/* params */});
Host umieszcza Twój IDocumentTab w pasku kart obok kart edytora i kieruje do
niego zapis/zamykanie. Karty zwracające niepuste sessionParams() są
przechwytywane przez utrwalanie sesji i odtwarzane przez openTab() przy
przywracaniu; jeśli w chwili przywracania brakuje wtyczki-właściciela, host
zbiera osierocone wpisy w jeden komunikat, zamiast je porzucać. Przykłady we
wtyczkach własnych projektu: Diff Compare i Log Analyzer.
Widok porównania¶
ctx.compare() otwiera dwupanelowe okno porównania edytora dla dowolnej pary
źródeł — ścieżek plików, otwartych dokumentów lub tekstu w pamięci:
CompareSource left{...}, right{...};
bool shown = ctx.compare().openCompare(left, right, CompareOptions{});
Zawsze bezpieczne do wywołania: host bez widoku porównania dostarcza no-op
zwracający false.
Pasek stanu¶
Dwa niezależne kanały — tymczasowe powiadomienia oraz trwałe segmenty należące do wtyczki:
// Transient: replaces/queues by severity; do NOT use for live state.
ctx.statusBar().showMessage("Wrapped", 2000, StatusLevel::Info);
// Persistent segment: an always-on indicator you own and refresh.
m_segment = ctx.statusBar().addSegment("wordcount.total");
m_segment->setText("2,431 words");
m_segment->setVisible(false); // hide without destroying
// dropping the unique_ptr removes the segment
Powiadomienie o wyższej wadze natychmiast zastępuje to widoczne na ekranie;
powiadomienie o niższej wadze może zostać na chwilę wstrzymane, aby Error nie
został od razu zmazany przez rutynowe Info. Odświeżanie segmentu nigdy nie
nadpisuje powiadomienia i odwrotnie.
Menu kontekstowe edytora¶
W odróżnieniu od IMenuRegistry — statycznych pozycji paska menu powiązanych z
poleceniami — pozycje menu kontekstowego są dynamiczne: przy każdym kliknięciu
prawym przyciskiem w obszarze tekstu host pyta każdego zarejestrowanego providera,
co ma zastosowanie w klikniętej pozycji, i dokleja odpowiedzi poniżej wbudowanych
akcji edycji (Cofnij/Ponów, Wytnij/Kopiuj/Wklej, Zaznacz wszystko):
class MyProvider final : public plugin::IContextMenuProvider
{
std::vector<plugin::ContextMenuItem>
contextMenuItems(const plugin::ContextMenuRequest& req) override
{
// req.doc + req.position (byte offset under the click; the caret
// for keyboard-triggered menus). Empty vector = decline.
if (!appliesAt(req.doc, req.position)) { return {}; }
return {
{ "Do the thing", [this, req] { doTheThing(req); } },
{ "", {} }, // empty title = separator
{ "Another action", [this] { another(); } },
};
}
};
m_token = ctx.contextMenu().registerProvider(m_provider); // RAII token
Providery działają w wątku UI, podczas gdy użytkownik czeka na menu — odpowiadaj ze stanu w pamięci, nigdy nie blokuj. Tytuły pozycji to dynamiczne stringi, które wtyczka tłumaczy samodzielnie. Sprawdzanie pisowni używa tego do swoich podpowiedzi / pozycji Dodaj do słownika / Ignoruj w tej sesji.
Paleta motywu¶
Wtyczki malujące własne kolory rejestrują nazwane kategorie z domyślnymi wartościami dla motywu jasnego/ciemnego i rozwiązują je do RGB w momencie malowania — nigdy nie hardkoduj kolorów:
// ThemeCategory: {id, displayLabel, defaultLight, defaultDark}.
// The id is namespaced "<plugin.id>/<role>" by convention.
m_cat = ctx.themePalette().registerCategory(
{"com.example.myplugin/match", "Match highlight",
/*light*/ 0xFFF3B0, /*dark*/ 0x8A6D00});
std::uint32_t rgb = ctx.themePalette().resolveColor("com.example.myplugin/match");
bool themed = ctx.themePalette().hasOverride("com.example.myplugin/match");
std::string variant = ctx.themePalette().activeVariant(); // "light" / "dark" / ""
resolveColor zwraca nadpisanie z motywu, jeśli istnieje, w przeciwnym razie
zarejestrowaną wartość domyślną dla aktywnego wariantu, a 0x000000 dla
niezarejestrowanego id (traktuj to jako „użyj własnego fallbacku").
Każda zarejestrowana kategoria automatycznie pojawia się w edytorze motywów,
a nadpisania użytkownika wędrują w obie strony w pliku motywu pod
pluginColors. Przemaluj przy events::ThemeChanged.