W pogoni za idealnym frameworkiem do GUI, zapomniałem o bardzo ważnej rzeczy:
Wielofunkcyjny scyzoryk nie zastąpi zestawu kluczy
Podobnie jest z wieloma innymi wielofunkcyjnymi rzeczami (np. smartfony nie zastąpią nigdy lustrzanek), więc również z frameworkami do GUI. Zarówno Xwt jak i Eto nie mogą w pełni wykorzystywać wszystkich obsługiwanych platform, ponieważ ich celem jest zapewnienie wspólnego API do tworzenia aplikacji na wiele platform. Zamiast tego należy zrobić to co ludzie robili od dawna: oddzielić interfejs użytkownika od logiki i wyodrębnić po jednym projekcie na każdą platformę.
Postawiłem na WPF na Windows oraz na GTK# na Linux/MacOS, aby obok cross-platformowości wspierać natywny wygląd dla platform, w które celuję (Windows i Linux). Postaram się np. korzystać z wbudowanych ikonek do których użytkownicy danej platformy są przyzwyczajeni.
Więc postanowiłem podzielić SharpOffice.Window.Runtime
na SharpOffice.Runtime.WPF
oraz SharpOffice.Runtime.GTK
. Z tego względu postanowiłem usunąć SharpOffice.Window
, które było zależne od Xwt. Mając dwa oddzielne (i jak różne) runtime’y, nie mogę mieć odwołań do obiektów używanych frameworków, a odwrócić te zależności.
W ten sposób aplikacje i pluginy będą korzystały z przestrzeni nazw SharpOffice.Core.Window
do definiowania klas opartych o zestaw interfejsów, które następnie będą w odpowiedni sposób czytane przez runtime i na ich podstawie będzie generowane okno aplikacji.
Żeby uzyskać automatyczne ładowanie odpowiednich elementów, będę musiał wzbogacić moją klasę ContainerWrapper
, której kod można zobaczyć tutaj, o dodatkowe ładowanie klas dotyczących zawartości okna. Np. IMenuComposer
, który odwołując się do singletonu IMenuProvider
, zawierającego listę menu najwyższego poziomu, dodaje odpowiednie pozycje, populując menu. Jeśli plugin będzie chciał mieć swoją pozycję w menu, wystarczy że zaimplementuje IMenuComposer
, w którym utworzy obiekt typu IMenuElement
i doda go do odpowiedniego menu.