Правильный способ установить цвета виджета GTK3 на вычисленное значение - PullRequest
1 голос
/ 11 июля 2019

В моем пользовательском интерфейсе (кодированном на Haskell) я хочу установить для некоторых цветов фона и переднего плана виджета значения, вычисленные приложением (в отличие от цвета темы). Для этого я изначально использовал widgetOverrideBackgroundColor и widgetOverrideColor, несмотря на то, что они устарели. Однако они недавно перестали работать (достаточно справедливо, они устарели).

Какой самый простой способ получить функционал widgetOverrideColor и его родственников? Есть ли способ программной генерации поставщика стиля для одного виджета и установки там цветов (виджеты также генерируются динамически)? Или это решение перехватить обратный вызов draw? Если да, то как я могу установить цвета и затем вернуть управление оригиналу?

Ответы [ 2 ]

1 голос
/ 13 июля 2019

Теперь мне удалось сделать это с помощью комбинации CSS и перехваченных draw сигналов. Код написан на Haskell, как и я, но он должен быть переведен на другие языки.

Основной метод заключается в добавлении некоторого дополнительного кода Cairo к обратному вызову draw для рисования другого фона, а затем с помощью CSS установите прозрачность самого виджета. Этот код использует библиотеку gi-gtk для GTK3, библиотеку cairo для рисования и библиотеку color для цветов. Это было извлечено и немного упрощено из более крупной программы. Надеюсь, я не оставил ничего висящего.

import qualified GI.Cairo.Structs.Context as Gtk
import qualified GI.Gtk as Gtk
import qualified Graphics.Rendering.Cairo as Cairo
import qualified Graphics.Rendering.Cairo.Internal as CI
import qualified Graphics.Rendering.Cairo.Types as Cairo (Cairo (Cairo))

import qualified Data.Colour as C
import qualified Data.Colour.CIE as C
import qualified Data.Colour.SRGB as C

customPaint :: (Gtk.isWidget w) => w -> Maybe Colour -> Gtk.Context -> IO ()

customPaint widget Nothing _ = do
     -- No background, so reset everything.
     style <- Gtk.widgetGetStyleContext widget
     mapM_ (Gtk.styleContextRemoveClass style) [lightClass, darkClass]

customPaint widget (Just c) ctx = do
     -- Get the dimensions of the background.
     w <- Gtk.widgetGetAllocatedWidth widget
     h <- Gtk.widgetGetAllocatedHeight widget
     -- Set the widget style to transparent using a class.
     style <- Gtk.widgetGetStyleContext widget
     mapM_ (Gtk.styleContextRemoveClass style) [lightClass, darkClass]
     Gtk.styleContextAddClass style $ if C.luminance c > 0.5 then lightClass else darkClass
     -- Draw the background using the Cairo Render monad.
     runRender ctx $ do
        let
           C.RGB r1 g1 b1 = C.toSRGB c
        Cairo.setSourceRGB r1 g1 b1
        Cairo.rectangle 0 0 (fromIntegral w) (fromIntegral h)
        Cairo.fill

  -- Conversion between gi-gtk Cairo Context and Cario library Render monad. Only
  -- needed because they have different ways of wrapping the underlying C object.
  runRender ctx action =
     Gtk.withManagedPtr ctx $ \p ->
        runReaderT (CI.runRender action) (Cairo.Cairo (castPtr p))

  -- CSS class names. "light" uses black text on a pale background. "dark" is the opposite.
  lightClass = "transparent-light"
  darkClass = "transparent-dark"

Затем вы можете сохранить нужный цвет в IORef и создать обратный вызов для сигнала рисования виджета, например:

Gtk.onWidgetDraw myWidget $ \ctx -> do
   c <- readIORef colourRef
   customPaint myWidget c ctx

CSS для приложения содержит следующее:

/* Custom CSS classes for coloured widgets.

The background is transparent. The foreground is either black or white.
*/
.hades-transparent-dark {
  color: white;
  background-color: transparent; }

.hades-transparent-light {
  color: black;
  background-color: transparent; }

К счастью, мне нужно только установить цвет фона, при этом цвет переднего плана будет черный или белый для контраста с фоном. Я не знаю, как бы я настроил произвольный цвет переднего плана.

0 голосов
/ 12 июля 2019

Документация GTK рекомендует использовать CSS:

gtk_widget_override_background_color устарела с версии 3.16 и не должна использоваться во вновь создаваемом коде.

Эта функция не полезна в контексте рендеринга на основе CSS.Если вы хотите изменить способ отображения фона виджетом, вы должны использовать собственный стиль CSS, используя GtkStyleProvider для конкретного приложения и класс стиля CSS.Вы также можете переопределить рисование виджета по умолчанию с помощью сигнала «рисовать» и использовать Cairo для рисования определенного цвета независимо от стиля CSS.

Для справки, в my ownПриложение GTK3 Я использовал следующий код для загрузки пользовательского CSS:

{-# LANGUAGE OverloadedStrings #-}

import GI.Gtk

main = do
    -- stuff
    prov <- cssProviderNew
    cssProviderLoadFromPath prov "path/to/custom/css/file.css"
    screenGetDefault >>= \case
        Just screen -> styleContextAddProviderForScreen screen prov 800
        Nothing -> return ()

Для самого файла CSS вы можете ссылаться на виджеты по их именам .Следующий CSS не протестирован, но должен работать:

#widgetname1 {
  color: red;
  background-color: green;
}

Я не знаю, есть ли способ сделать это чисто программно, без каких-либо внешних файлов CSS (т. Е. С указанием встроенного CSS);если я найду метод, я обновлю этот ответ.

...