Code Monkey home page Code Monkey logo

monomer's Introduction

Monomer

A cross-platform GUI library for Haskell

Logo

CI badge made with Haskell BSD-3-Clause


An easy to use, cross platform, GUI library for writing native Haskell applications.

Monomer provides a framework similar to the Elm Architecture, allowing the creation of GUIs using an extensible set of widgets with pure Haskell.

Objectives

  • Be easy to learn and use.
  • Be extensible with custom widgets.
  • Run on Windows, Linux and macOS.
  • Have good documentation.
  • Have good examples.

These are not objectives for this project

  • Have a native look and feel.

Why would you want to use this library?

  • You want to write your application in Haskell.
  • You want to write a native, not web based, application.

Documentation

Setup

You can read how to setup your environment here.

Tutorials

Introductory tutorials are available:

Examples

Beyond the tutorials, a few real world like examples are available:

Haddock

You can read the source code's documentation here.

Design decisions

In case you wonder why some choices were made, you can read here.

Roadmap

  • Stability and performance.
  • Mobile support.

Project status

Although there has not been a lot of activity in the past year, the project is still active.

I may take some time to respond to issues while I work on features I want to add to Monomer.

Useful extensions

Contributing

PRs are welcome!

If possible, keep them small and focused. If you are planning on making a large change, please submit an issue first so we can agree on a solution.

License

This library is licensed under the BSD-3 license.

Fonts used in the examples:

Acknowledgments

monomer's People

Contributors

camdenkuwahara avatar chreekat avatar clindbergh avatar darinm223 avatar deltaspace0 avatar dretch avatar fjvallarino avatar hasufell avatar jhrcek avatar klausweiss avatar kyarigwo avatar rubenastudillo avatar smunix avatar toku-sa-n avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

monomer's Issues

Missing 'freetype2' for windows build

nanovg complained about missing freetype2, but fixed with

stack exec -- pacman -S mingw-w64-x86_64-freetype

Not sure if I was missing something or the instructions on the readme where incomplete

Possible numericField bug (value lost when type of number changes)

Hello, this library has a really nice design and docs, so thanks!

I have found what might be a bug (possibly I just misunderstand how things should be working, though).

I have a numericFieldV that stays in the same position in the widget tree, but sometimes contains an Integer value and other times contains a Float. The value is preserved as much as possible (using truncate/fromIntegral) when switching between the types.

I expected the value to stay showing (just changing whether it has a fractional part or not) when the type changes, but instead the numeric field loses the value and goes back to empty. This is demonstrated by this modification of the helloworld example: monomer-numeric-field-issue.zip

Rationale: why not optics library?

I see that you took lens rather than microlens for a good reason, but I wonder why you did not choose the optics library - which gives near perfect support with less dependency footprint.

Edge case where label text is not displayed

Hello,

I have found an edge case where the text on a label does not get drawn.

The UI code looks like this:

buildUI
  :: WidgetEnv AppModel AppEvent
  -> AppModel
  -> WidgetNode AppModel AppEvent
buildUI wenv _model =
  hstack [
    label "a" `styleBasic` [paddingH 4]
  ]

Reducing paddingH to 3 makes the "a" show up. Changing "a" to "b" also makes the text show up.

Example with text not showing:
Screenshot at 2021-12-31 12-49-43

Example with text changed to "b" and therefore showing:
Screenshot at 2021-12-31 12-50-11

I have also attached a modified hello world that demonstrates this phenomenon:
monomer-label-text-not-displayed.zip

I suppose there is some edge case in the text rendering code that is not working quite correctly.

PS. Sorry for logging bugs! My experience with Monomer is actually really positive: I am converting a gi-gtk-declarative app and although it is not completely trivial (e.g. I am hacking together a 2d-grid container like Gtk Grid), it has been pretty easy to bend Monomer to my will.

DPI calculation discussion

Hi, I've created this item to continue discussion of the DPI issues raised in #54.

On my machine I have 3 monitors, two are 2560x1440 resolution and one is 1920x1080. By default the application is opening on one of the 2560x1440 monitors, which is the primary display, however when @fjvallarino mentioned that Platform.hs does some calculations on startup, I tried opening it on my other monitors by setting them as primary. The other 2560x1440 monitor also has this issue, but the 1920x1080 monitor does not.

Bug: onBtnPressed ignores middle mouse button clicks

A box with onBtnPressed / onBtnReleased completely ignores clicks on the middle mouse button.

Here's a small isolated example.

example
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}

module Main where

import Control.Lens
import Data.Maybe
import Data.Text (Text, pack)
import Monomer
import TextShow

import qualified Monomer.Lens as L

newtype AppModel = AppModel {
  _lastClick :: Text
} deriving (Eq, Show)

data AppEvent
  = AppInit
  | LastClick Text
  deriving (Eq, Show)

makeLenses 'AppModel

buildUI
  :: WidgetEnv AppModel AppEvent
  -> AppModel
  -> WidgetNode AppModel AppEvent
buildUI wenv model = widgetTree where
  widgetTree =
      box_ [expandContent, onBtnPressed handleClick]
        (label (model ^. lastClick) `styleBasic` [textCenter])

handleClick b times = LastClick $ pack (show b) <> " pressed " <> showt times <> " times"

handleEvent
  :: WidgetEnv AppModel AppEvent
  -> WidgetNode AppModel AppEvent
  -> AppModel
  -> AppEvent
  -> [AppEventResponse AppModel AppEvent]
handleEvent wenv node model evt = case evt of
  AppInit -> []
  LastClick t -> [Model (model & lastClick .~ t)]

main :: IO ()
main = do
  startApp model handleEvent buildUI config
  where
    config = [
      appWindowTitle "Hello world",
      appTheme darkTheme,
      appFontDef "Regular" "./assets/fonts/Roboto-Regular.ttf",
      appInitEvent AppInit
      ]
    model = AppModel "No button presses yet"

Tested on:

  • Void Linux PC (mouse)
  • Void Linux laptop (touchpad)
  • Windows 10 laptop (mouse)

with Monomer 1.2.0.0

accessing data files from monomer examples

In order to make deployment a little more portable, can we use the following APIs provided by cabal?
https://cabal.readthedocs.io/en/3.4/cabal-package.html#accessing-data-files-from-package-code

Without that, running the example binaries (/my/very/path/opengl for instance) fail to find the fonts and the vertex files.

Renderer: NVIDIA GeForce GTX 770/PCIe/SSE2
Version: 3.2.0 NVIDIA 470.86
Failed to load font: Regular
Could not find any valid fonts. Text size calculations will fail.

@fjvallarino let me know if you'd like me to push a PR

Suggestion: add the `forcebreak` option to `labelCfg`

Hi.

Currently label_ with the multiline option only breaks lines at the spaces. Unfortunately, this is not useful for languages that don't use spaces to separate words (e.g., CJK).

What I'm thinking is to add the forcebreak option to labelCfg, which allows breaking lines even in the middle of a word. This is not ideal because it ignores the grammatical rule. For example, punctuations may be positioned at the beginning of a line. However, I think considering the rules is difficult.

If adding the forcebreak option is acceptable, I'll send a PR (although I may need some help implementing it).

Question on Producers

How can I stop Producers and later restart it?
So if a Producer is relevant for some part of the application, which might be inactive / active / inactive ...

How can I access the model from within a producer?
So if a Producer might change its behaviour based on differences in the appmodel, e.g. changes threadDelay

Issue using some container widgets

I could be totally off base but I am not able to use some container widgets like box and hsplit in a definition like box . label $ "foo",
due to this warning:
No instance for (Typeable s) arising from a use of โ€˜boxโ€™
I am unable to use box with any widget that I tried, aliasing the box function box' = box showed the same warning in the definition so it doesn't appear only when applying box to other widgets.

I wrote some aliases for label and box:

_label :: (Typeable s, Typeable e) => Text -> WidgetNode s e
_label = label

_box :: (Typeable s, Typeable e) => WidgetNode s e -> WidgetNode s e
_box = box

__box :: (WidgetModel s, WidgetEvent e) => WidgetNode s e -> WidgetNode s e
__box = box

_t :: (Typeable s, Typeable e) => Text -> WidgetNode s e
_t = _box . _label

And this definition of _box and __box does not show the warning itself but I am still unable to apply it to either label or _label, though the definition _t shows no warning until it is applied to some Text.
Also tried reverting from monomer-1.3.0.0 to monomer-1.2.0.0 but had the same issue. This may be kind of a noob Haskell problem and not related to Monomer at all so I apologize if this is not worth a ticket.

How to create dialog window?

Hello, I wonder how I could create a dialog in separate window with monomer. How would I go with this?
Also I wonder if there is a way to have optional UI element which pops up only in certain circumstances without having to record the locql state in the monolithic state, for separation of concerns.
Thanks in advance!

Affects other windows on Linux (KDE)

First of all, thank you for this awesome library! I have a few Haskell projects that are missing GUIs, looking forward to give Monomer a try!

One weird issue though: I ran the first tutorial file (the one with click count), and the GUI seems to affect the other windows on my desktop. They are blinking on startup, and my Firefox tab goes completely blank. Any ideas what might cause this?

Config option for setting a minimum thumb size

I have a problem with scroll scroll_ etc.

In my application I create a vstack with a list of Widgets I create similar to the todo or books example. But my list, based on a xml file I parse is sometimes very large, like 2000 - 3000 items. And sometimes the xml file is shorter hence only 100 - 200 items.

in the case of the very large lists, the thum in the scroll bar becomes very tiny.

2022-01-14 18_08_30-Windows PowerShell

my "solution" was to simply copy the source for Monomer.Widgets.Containers.Scrolll and manually make something like

scrollStatus
  :: ScrollCfg s e
  -> WidgetEnv s e
  -> WidgetNode s e
  -> ScrollState
  -> Point
  -> ScrollContext
scrollStatus config wenv node scrollState mousePos = ScrollContext{..} where
...
  hThumbRect = Rect {
    _rX = caLeft - hScrollRatio * dx,
    _rY = caTop + hScrollTop + (barW - thumbW) / 2,
    -- old   _rW = hScrollRatio * vpWidth,
    _rW = minimal $ hScrollRatio * vpWidth,
    _rH = thumbW
  }
  vThumbRect = Rect {
    _rX = caLeft + vScrollLeft + (barW - thumbW) / 2,
    _rY = caTop - vScrollRatio * dy,
    _rW = thumbW,
   -- old _rH = vScrollRatio * vpHeight
    _rH = minimal $ vScrollRatio * vpHeight
  }

minimal x
   | x < 50      = 50
   | otherwise = x

Best place to go for new-user-type questions?

Hiya,

I'm enjoying the library and making baby steps in writing my own gui app for the first time ever.

I think I'm making some basic user mistakes -- they're not bugs, I just don't know what I'm doing. Is there any sort of community space for library users to congregate and discuss such things?

UI not updating immediately when the button that is clicked on is removed (bug?)

Hello!

I think this is probably a bug -- it is certainly unexpected:

  • I have a widget that contains a button.
  • When the button is clicked, the state is changed such that the entire widget tree is replaced by a different widget tree.
  • When this happens, the screen goes blank instead of showing the new widget immediately -- this is the bug!
  • However, when the mouse is moved a little, then the new widget appears.

I have attached a modification of the hello-world starter that demonstrates the issue: monomer-ui-not-updating-issue.zip

I guess this is somehow related to the button that is being clicked on being removed, since the issue does not seem to occur if clicking on the button leaves the button as-is but causes a different widget to be replaced.

An image generated by `imageMem` doesn't respond any events

I want to make an application that shows a part of an image file and move the part with arrow keys. The repository is here. (Note that this repository doesn't contain a font file. Please copy the one from the monomer-starter repository.)

When I press the arrow keys, the values of _position in AppModel change, but the image doesn't change.

simplescreenrecorder-2021-11-16_14.16.40.mp4

However, if I change the initial position, the result is what I expected.

16-11-2021_14 15 50_screenshot

So I thought the image generated by imageMem didn't respond to any events. Is this the expected behavior?

GHC version: 8.10.7
cabal version: 3.6.2.0

Problems with viewport

Viewports that i am getting from wenv ^. L.widgetKeyMap . at (WidgetKey name) are always Rect {_rX = 0.0, _rY = 0.0, _rW = 0.0, _rH = 0.0}, Is this a bug or i just miss something? I need a way to make some points inside a big scroll, i give them their nodeKey, and then i am trying to get a viewport of one of them to send it with ScrollTo. Could you please help ?

I finally found some time to revisit this.

(I could find how to reopen the issue 83#)

I finally found some time to revisit this.

grafik

I was able to add the following functionallities:

  • Syntaxhighlighting
  • Linenumbers && highlighted current linenumber
  • Highlight current Line
  • Selection works as expected
    all handled by config options for textArea.

Two things though:

  • It could not fix the jumping of the linenumbers - I tried to remove the padding as you suggested, but it still jumps back and forth
  • My syntaxhighlighting method looks okay, but if you switch it on an off ... there is movement in the text, so I make mistakes in my alignment of the text

Maybe you have a tip on how to deal with these two things

This is the code for the renderer in TextAreaWidget (I'm using a open repo for this with only the nesseary code - whole monomer took quite long to build everytime):

  render wenv node renderer = do
    let font = fromMaybe def (style ^? L.text . _Just  . L.font . _Just)
    let fontSize = fromMaybe def (style ^? L.text . _Just . L.fontSize . _Just)

    -- Highlight current line
    let textLinesRect   = wenv ^. L.viewport & L.x +~ lineNumberWidth
    drawInScissor renderer True textLinesRect $
      drawInTranslation renderer offset $ do
      case _tacCurrentLineColor config of
        Nothing -> return ()
        color   -> do
          let indexCurrentLine   = snd $ _tasCursorPos state
          let currentLine        = Seq.index textLines indexCurrentLine
          let (Rect tx ty tw th) = _tlRect currentLine
          let maxLineLength      = Seq.foldlWithIndex (\startValue _ textLine -> do
                                                          let tmpLength = _rW (_tlRect textLine)
                                                          if tmpLength >= startValue
                                                            then tmpLength
                                                            else startValue) 0 textLines
          drawRect renderer (Rect (-10) (ty-5) (10+maxLineLength) (th+10)) color Nothing

      when selRequired $
        forM_ selRects $ \rect ->
          when (rect ^. L.w > 0) $
            drawRect renderer rect (Just selColor) Nothing
        

      -- Syntax Highlighting
      case _tacSyntax config of
        -- Apply syntax highlighting
        Just (Just syntaxTree,syntaxMap) -> do
          let textLines' = Seq.mapWithIndex (\index value -> value & L.fontSize .~ fontSize) textLines
          MyDrawing.drawTextSyntaxed renderer style syntaxTree syntaxMap textLines'
        -- No syntax highlighting
        _          -> do
          let textLines' = Seq.mapWithIndex (\index value -> value & L.fontSize .~ fontSize) textLines
          forM_ textLines' (drawTextLine renderer style)

      when caretRequired $
        drawRect renderer caretRect (Just caretColor) Nothing


    -- draw LineNumbers
    let lineNumbersRect = wenv ^. L.viewport & L.w .~ lineNumberWidth
    let otherStyle color = style & L.text . non def . L.fontColor ?~ color
    let rH' = if textLines ==  Seq.empty
              then 5
              else do
          let line   = Seq.index textLines 0
          let space  = unFontSpace $ _tlFontSpaceV line
          let height = _rH $ _tlRect line
          height + space
    let textLine t y = do
          let wvp = fromMaybe (wenv ^. L.viewport) (removeOuterBounds style (wenv ^. L.viewport))
          let rect' = wvp & L.x +~ 5 & L.y .~ y & L.w .~ 20 & L.h .~ 20
          --let rect' = Rect (wenv ^. L.viewport ^. L.x + 5) y 20 20
          def
            & L.text .~ t
            & L.rect .~ rect'
            & L.fontSize .~ fontSize
            & L.font .~ font
    let renderLineNumber = renderIndexLine . createIndexLine
          where
            lineStyle index =
              otherStyle $ if index==succ (snd $ _tasCursorPos state)
                           then rgbHex "#ff2200"
                           else rgbHex "#000000"
            renderIndexLine (index,line) = drawTextLine renderer (lineStyle index) line
            createIndexLine x            = (x,textLine (T.pack $ show x) (35 + fromIntegral x * rH'))
    when (fromMaybe False (_tacShowLineNumbers config)) $ do
        drawRect renderer lineNumbersRect (Just (fromMaybe (rgbHex "#ff2200") (style ^. L.sndColor))) Nothing
        drawInScissor renderer True lineNumbersRect $ do
          mapM_ renderLineNumber [1..length textLines]
    where
      style = currentStyle wenv node
      contentArea = getContentArea node style
      ts = _weTimestamp wenv
      offset = Point (lineNumberWidth + contentArea ^. L.x) (contentArea ^. L.y)
      focused = isNodeFocused wenv node

      caretTs = ts - _tasFocusStart state
      caretRequired = focused && even (caretTs `div` caretMs)
      caretColor = styleFontColor style
      caretRect = getCaretRect config state False

      selRequired = isJust (_tasSelStart state)
      selColor = styleHlColor style
      selRects = getSelectionRects state contentArea

Originally posted by @simmihugs in #83 (comment)

Feature request: text widget that is selectable but not editable

Hello,

It would be useful for me to have a widget that displays text that can be selected (and copied), but cannot be edited.

Currently I don't think this exists: textfield/areas can be disabled to stop editing, but then you can't select the text either. Labels don't currently allow selecting.

Could textfield/area perhaps have a readonly option? I can probably send a PR.

Ghcid not working properly

I tried using ghcid for development. After saving a file, the original app window stays open and another one opens and the app cannot be stopped normally, I have to Ctrl+C the ghcid command itself. So, I basically cannot use ghcid for development. Screenshots:

  • First open of the app

image

  • After saving a file

image

Public API contains not-exported types.

There's quite a few places in the API where Haddocks mention some type, but that type is not exposed from the available modules.

Few examples of this:

  • EventReponse mentions TaskHandler, but this type is nowhere to be found in the haddocks.

  • Button mentions ButtonCfg, but again that type is not exposed so it's unclear what could be passed in that list.

In haddocks this manifests as the unexposed type not being rendered as link. e.g.
Screenshot from 2021-08-12 13-19-51

Unbuildable

This package was uploaded to hackage but is unbuildable, due to:

monomer/stack.yaml

Lines 46 to 49 in 523355c

extra-deps:
- git: https://github.com/fjvallarino/nanovg-hs
commit: ba8733f58da63e0934b5d2853ed84b71e872e6f1
- regex-posix-clib-2.7@sha256:998fca06da3d719818f0691ef0b8b9b7375afeea228cb08bd9e2db53f96b0cd7,1232

$ cabal install monomer                                                                                                                      2516ms ๎‚ณ Sat 09:28
cabal: Could not resolve dependencies:
[__0] trying: monomer-1.0.0.1 (user goal)
[__1] next goal: nanovg (dependency of monomer)
[__1] rejecting: nanovg-0.6.0.0 (conflict: monomer => nanovg>=0.8 && <1.0)
[__1] skipping: nanovg-0.5.2.0, nanovg-0.5.1.0, nanovg-0.5.0.0,
nanovg-0.4.0.0, nanovg-0.3.0.0, nanovg-0.2.0.0, nanovg-0.1.0.2,
nanovg-0.1.0.1, nanovg-0.1.0.0 (has the same characteristics that caused the
previous version to fail: excluded by constraint '>=0.8 && <1.0' from
'monomer')
[__1] fail (backjumping, conflict set: monomer, nanovg)
After searching the rest of the dependency tree exhaustively, these were the
goals I've had most trouble fulfilling: monomer, nanovg

Install on Windows does not work

In the installation on Windows procedure (as descibed in 00-setup.md),

stack exec -- pacman -S mingw-w64-x86_64-pkg-config

will report the following errors:

error: mingw32: key "FA11531AA0AA7F57" is unknown
error: key "FA11531AA0AA7F57" could not be looked up remotely
error: mingw64: key "FA11531AA0AA7F57" is unknown
error: key "FA11531AA0AA7F57" could not be looked up remotely
error: msys: key "FA11531AA0AA7F57" is unknown
error: key "FA11531AA0AA7F57" could not be looked up remotely
error: database 'mingw32' is not valid (invalid or corrupted database (PGP signature))
error: database 'mingw64' is not valid (invalid or corrupted database (PGP signature))
error: database 'msys' is not valid (invalid or corrupted database (PGP signature))

I have no idea what is going on, even after googling a lot.
"pacman -Syu" fails with similar errors.
Is it possible to update 00-setup.md to describe what has to be done?

Thanks
Robert

Wheelrate for textArea

textArea is automatically inside scroll - correct?
now, textArea_ does not have cfg for wheelrate

how can I reach the wheelrate of the implicit scroll of textArea?

install failure on mac m1

Found this project via https://www.reddit.com/r/haskell/comments/p12pjs/ann_monomer_a_gui_library_for_haskell. Thank you very much!

Installing went well up to this point:

06:27:37 ~/src/GUI/monomer-starter$ stack build 
...
monomer        > configure
monomer        > Configuring monomer-1.0.0.0...
monomer        > build
monomer        > Preprocessing library for monomer-1.0.0.0..
monomer        > Building library for monomer-1.0.0.0..
monomer        > [  1 of 102] Compiling Monomer.Common.BasicTypes
monomer        > [  2 of 102] Compiling Monomer.Common
monomer        > [  3 of 102] Compiling Monomer.Common.Lens
monomer        > <command line>: dlopen(/opt/homebrew/lib/libSDL2.dylib, 5): no suitable image found.  Did find:
monomer        > 	/opt/homebrew/lib/libSDL2.dylib: mach-o, but wrong architecture
monomer        > 	/opt/homebrew/Cellar/sdl2/2.0.14_1/lib/libSDL2-2.0.0.dylib: mach-o, but wrong architecture
Progress 1/2

--  While building package monomer-1.0.0.0 (scroll up to its section to see the error) using:
      /Users/simon/.stack/setup-exe-cache/x86_64-osx/Cabal-simple_mPHDZzAJ_3.2.1.0_ghc-8.10.4 --builddir=.stack-work/dist/x86_64-osx/Cabal-3.2.1.0 build --ghc-options " -fdiagnostics-color=always"
    Process exited with code: ExitFailure 1

Not sure if it's an artifact of my machine, or a general problem for all mac m1 users.

06:27:49 ~/src/GUI/monomer-starter$ brew install sdl2
Warning: sdl2 2.0.14_1 is already installed and up-to-date.
To reinstall 2.0.14_1, run:
  brew reinstall sdl2
06:31:46 ~/src/GUI/monomer-starter$ brew list sdl2
brew list sdl2
/opt/homebrew/Cellar/sdl2/2.0.14_1/bin/sdl2-config
/opt/homebrew/Cellar/sdl2/2.0.14_1/include/SDL2/ (76 files)
/opt/homebrew/Cellar/sdl2/2.0.14_1/lib/libSDL2-2.0.0.dylib
/opt/homebrew/Cellar/sdl2/2.0.14_1/lib/cmake/ (2 files)
/opt/homebrew/Cellar/sdl2/2.0.14_1/lib/pkgconfig/sdl2.pc
/opt/homebrew/Cellar/sdl2/2.0.14_1/lib/ (4 other files)
/opt/homebrew/Cellar/sdl2/2.0.14_1/share/aclocal/sdl2.m4
06:32:02 ~/src/GUI/monomer-starter$ file /opt/homebrew/Cellar/sdl2/2.0.14_1/lib/libSDL2-2.0.0.dylib
/opt/homebrew/Cellar/sdl2/2.0.14_1/lib/libSDL2-2.0.0.dylib: Mach-O 64-bit dynamically linked shared library arm64

Add support for Nix

To make reproducible builds possible for users, should we add support for Nix? I'm sitting ready to push a PR if this is a feature users would want to have.

Also thanks for putting this up, I've been waiting on such a framework for a long time now.

Beginner Question - Focus on TextArea

TextArea does not allow me to type in it, unless I click with my Mouse into the Textarea.

My application has a TextField. When I set the focus to the TextField with SetFocusOnKey "textField1"
--> I can type in the TextField right away; As expected

My app also has a TextArea. When I set the focus to the TextArea with SetFocusOnKey "textArea1"
--> I cannot type in the TextArea unless I click with my Mouse into the TextArea
The TextArea, I did not change the the theme, has a blue border when it is on Focus, but there is no Cursor
--> blue border so it is focused

How do I make TextAreas accept input after receiving focus?

P.S. if there is a better way to ask trivial questions like this, let me know

Feature request: allow setting the window icon

I think it would be great if AppConfig allowed setting the window icon.

As far as I can see (hopefully I am wrong!), the Haskell SDL package does not currently provide any way of doing this that does not involve unsafeCoerce (to turn SDL.Video.Window into Ptr ()), so this would involve a feature request/PR to that project too.

If this is considered desirable, I can put together the necessary PRs.

Ubuntu: NVIDIA RTX A6000 - Unable to make GL context current

Hey all, I'm trying to build monomer on Ubuntu and no matter what I do in the build process (stack clean, recloning the repo, reinstalling nvidia drivers) I get this error when trying to run any example apps:

Renderer: NVIDIA RTX A6000/PCIe/SSE2
Version: 3.2.0 NVIDIA 470.103.01
generative: SDLCallFailed {sdlExceptionCaller = "SDL.Video.OpenGL.glMakeCurrent", sdlFunction = "SDL_GL_MakeCurrent", sdlExceptionError = "Unable to make GL context current"}

I ran a debug trace(LD_DEBUG=libs stack run generative) which tracked down this error when running stack run generative (for example):

76922: /lib/x86_64-linux-gnu/libnvidia-glcore.so.470.103.01: error: symbol lookup error: undefined symbol: ErrorF (fatal)

Any help is appreciated I'm at something of a loss

nanovg is marked as broken on nixpkgs

Hi,

I've been wanting to try out this library for a while since it looks great (thanks for making it!) but I am having issues using it due to the nanovg dependency not building on Nixpkgs.

I know this is more an issue of nanovg but it's not a very active project so I've seen you contributed to it and might have an idea on how I can get this working? Even if you don't use Nix, it might be of help to have this issue as a reference for other potential users out there, in case we can figure out a solution :)

Here's what I've tried in my Haskell packages override, building against GHC 8.10.4 (also tried 8.8.4, same issue).

diff --git a/fts.cabal b/fts.cabal
index d1cb5c0..6625d9e 100644
--- a/fts.cabal
+++ b/fts.cabal
@@ -22,6 +22,8 @@ library
                      , containers
                      , exceptions
                      , managed
+                     --, monomer
+                     , nanovg
                      , postgresql-resilient
                      , postgresql-simple
                      , prettyprinter
diff --git a/nix/pkgs.nix b/nix/pkgs.nix
index 2513c12..a3fe948 100644
--- a/nix/pkgs.nix
+++ b/nix/pkgs.nix
@@ -11,6 +11,33 @@ let
 
   hp = pkgs.haskell.packages.${compiler}.override {
     overrides = new: old: rec {
+      #monomer =
+      #pkgs.haskell.lib.dontCheck (
+      #new.callCabal2nix "monomer" (
+      #builtins.fetchGit {
+      #url = "https://github.com/fjvallarino/monomer.git";
+      #rev = "c1903ed153243aadb12a838bfc1238b4e25a6bcf";
+      #}
+      #) { GLEW = pkgs.glew; }
+      #);
+
+      nanovg =
+        pkgs.haskell.lib.dontCheck (
+          new.callCabal2nixWithOptions "nanovg" (
+            builtins.fetchGit {
+              url = "https://github.com/cocreature/nanovg-hs.git";
+              rev = "65904d0b28fe94f3e531e82ad0dcda6b7b2eb8d9";
+            }
+          ) "-fexamples" {
+            GLEW = null;
+            inherit (pkgs) freetype;
+            inherit (pkgs) glew;
+            inherit (pkgs) libGL;
+            inherit (pkgs) libGLU;
+            inherit (pkgs.xorg) libX11;
+          }
+        );
+
       postgresql-resilient =
         pkgs.haskell.lib.dontCheck (
           new.callCabal2nix "postgresql-resilient" (

Which yields the following error, upon evaluation:

building
Preprocessing library for nanovg-0.7.0.0..
dist/build/NanoVG/Internal.chs.h:2:10: fatal error: nanovg.h: No such file or directory
    2 | #include "nanovg.h"
      |          ^~~~~~~~~~
compilation terminated.
c2hs: Error during preprocessing custom header file
builder for '/nix/store/3zagfr0cy0vm8461g2dn1mfsr40ch1d0-nanovg-0.7.0.0.drv' failed with exit code 1
cannot build derivation '/nix/store/p9585jifalhshgrz8vi0asdr1w5qlbsa-ghc-8.10.4-with-packages.drv': 1 dependencies couldn't be built
error: build of '/nix/store/p9585jifalhshgrz8vi0asdr1w5qlbsa-ghc-8.10.4-with-packages.drv' failed

I'd appreciate any help I can get ๐Ÿ™๐Ÿฝ

memory leak with Ticker?

I left Ticker (in the example) running for about 1 hour, it generated about 27GiB of RSS, with 32GiB of swap space depleted. This is on Linux. Will investigate later

None of the examples build on Linux (specifically Ubuntu 21.04)

monomer/examples/ticker> stack build
... a bunch of compiling output...

--  While building package generic-deriving-1.13.1 (scroll up to its section to see the error) using:
      /home/jesse/.asdf/installs/haskell/9.0.1/stack/setup-exe-cache/x86_64-linux-tinfo6/Cabal-simple_mPHDZzAJ_3.4.0.0_ghc-9.0.1 --builddir=.stack-work/dist/x86_64-linux-tinfo6/Cabal-3.4.0.0 build --ghc-options " -fdiagnostics-color=always"
    Process exited with code: ExitFailure 1


--  While building package memory-0.15.0 (scroll up to its section to see the error) using:
      /home/jesse/.asdf/installs/haskell/9.0.1/stack/setup-exe-cache/x86_64-linux-tinfo6/Cabal-simple_mPHDZzAJ_3.4.0.0_ghc-9.0.1 --builddir=.stack-work/dist/x86_64-linux-tinfo6/Cabal-3.4.0.0 build --ghc-options " -fdiagnostics-color=always"
    Process exited with code: ExitFailure 1


--  While building package profunctors-5.5.2 (scroll up to its section to see the error) using:
      /home/jesse/.asdf/installs/haskell/9.0.1/stack/setup-exe-cache/x86_64-linux-tinfo6/Cabal-simple_mPHDZzAJ_3.4.0.0_ghc-9.0.1 --builddir=.stack-work/dist/x86_64-linux-tinfo6/Cabal-3.4.0.0 build --ghc-options " -fdiagnostics-color=always"
    Process exited with code: ExitFailure 1


--  While building package formatting-6.3.7 (scroll up to its section to see the error) using:
      /home/jesse/.asdf/installs/haskell/9.0.1/stack/setup-exe-cache/x86_64-linux-tinfo6/Cabal-simple_mPHDZzAJ_3.4.0.0_ghc-9.0.1 --builddir=.stack-work/dist/x86_64-linux-tinfo6/Cabal-3.4.0.0 build --ghc-options " -fdiagnostics-color=always"
    Process exited with code: ExitFailure 1
monomer/examples/generative> stack build
... a bunch of compiling output...

--  While building package generic-deriving-1.13.1 (scroll up to its section to see the error) using:
      /home/jesse/.asdf/installs/haskell/9.0.1/stack/setup-exe-cache/x86_64-linux-tinfo6/Cabal-simple_mPHDZzAJ_3.4.0.0_ghc-9.0.1 --builddir=.stack-work/dist/x86_64-linux-tinfo6/Cabal-3.4.0.0 build --ghc-options " -fdiagnostics-color=always"
    Process exited with code: ExitFailure 1


--  While building package memory-0.15.0 (scroll up to its section to see the error) using:
      /home/jesse/.asdf/installs/haskell/9.0.1/stack/setup-exe-cache/x86_64-linux-tinfo6/Cabal-simple_mPHDZzAJ_3.4.0.0_ghc-9.0.1 --builddir=.stack-work/dist/x86_64-linux-tinfo6/Cabal-3.4.0.0 build --ghc-options " -fdiagnostics-color=always"
    Process exited with code: ExitFailure 1


--  While building package profunctors-5.5.2 (scroll up to its section to see the error) using:
      /home/jesse/.asdf/installs/haskell/9.0.1/stack/setup-exe-cache/x86_64-linux-tinfo6/Cabal-simple_mPHDZzAJ_3.4.0.0_ghc-9.0.1 --builddir=.stack-work/dist/x86_64-linux-tinfo6/Cabal-3.4.0.0 build --ghc-options " -fdiagnostics-color=always"
    Process exited with code: ExitFailure 1


--  While building package formatting-6.3.7 (scroll up to its section to see the error) using:
      /home/jesse/.asdf/installs/haskell/9.0.1/stack/setup-exe-cache/x86_64-linux-tinfo6/Cabal-simple_mPHDZzAJ_3.4.0.0_ghc-9.0.1 --builddir=.stack-work/dist/x86_64-linux-tinfo6/Cabal-3.4.0.0 build --ghc-options " -fdiagnostics-color=always"
    Process exited with code: ExitFailure 1

I can go back and get the other ones later, if that would help. I know they're dependencies but I'd love to play around with the demos.

Typed keystrokes

Right now, keystrokes are specified using a String, which I don't think is ideal, because a lot can go wrong. For example, putting in an empty string as a keystroke gives a runtime error after pressing any key and the app crashes:

app: Data.Text.Internal.Fusion.Common.index: Index too large
CallStack (from HasCallStack):
  error, called at libraries/text/src/Data/Text/Internal/Fusion/Common.hs:943:24 in text-1.2.4.1:Data.Text.Internal.Fusion.Common

I think it would be better to add a type for defining keystrokes like this:

data KeyCombination = KeyCombination (Set ModKey) SingleKey

data ModKey = Ctrl | Alt | Shift deriving Eq

data SingleKey = Enter | Tab | ...other functional keys... | CharKey Char

That way the API would be much more typesafe and wouldn't just rely on the correctness of the string.

Consider creating a separate package for examples

Depending on monomer also pulls in websocket, wreq, etc which then depends on the http stack which... a simple application that doesn't use any of those libraries doesn't need as a transitive dependency.

Could we move those dependencies for the examples to a package like monomer-examples or some such?

Problem with linking stage in static builds

For the past few days, I've been trying to build a static executable of a monomer app. I'm now stuck on a linking problem.

/usr/lib/gcc/x86_64-alpine-linux-musl/10.3.1/../../../../x86_64-alpine-linux-musl/bin/ld: cannot find -lGLU
/usr/lib/gcc/x86_64-alpine-linux-musl/10.3.1/../../../../x86_64-alpine-linux-musl/bin/ld: cannot find -lGL
/usr/lib/gcc/x86_64-alpine-linux-musl/10.3.1/../../../../x86_64-alpine-linux-musl/bin/ld: cannot find -lX11
/usr/lib/gcc/x86_64-alpine-linux-musl/10.3.1/../../../../x86_64-alpine-linux-musl/bin/ld: cannot find -lX11
/usr/lib/gcc/x86_64-alpine-linux-musl/10.3.1/../../../../x86_64-alpine-linux-musl/bin/ld: cannot find -lGLU
/usr/lib/gcc/x86_64-alpine-linux-musl/10.3.1/../../../../x86_64-alpine-linux-musl/bin/ld: cannot find -lGL
/usr/lib/gcc/x86_64-alpine-linux-musl/10.3.1/../../../../x86_64-alpine-linux-musl/bin/ld: cannot find -lGLU
/usr/lib/gcc/x86_64-alpine-linux-musl/10.3.1/../../../../x86_64-alpine-linux-musl/bin/ld: cannot find -lGL

It says basically that GL, GLU and X11 libraries are missing, but they're installed and in /usr/lib, so I see no reason why it's failing. Here's a simple repo with the official example and a Dockerfile:

https://github.com/sproott/monomer-static-build-problem

To run the build, do docker build ..

SetFocusOnKey misbehaving with textArea

Hey. First of all, thanks for monomer!

I think SetFocusOnKey is not handled as it's supposed to with textArea. The widget seems to be focused, but the text is not editable until after I press the tab key.

To illustrate this I've come up with a minimal example (code below). It consists of a textField and a textArea both modifying the same text. When you switch between them with tab, the text is editable immediately. If you use C-p to select the textArea, said issue occurs. Selecting textField with C-o works properly, so I guess the issue lays in textArea's way of handling SetFocusOnKey. See the video below:

textarea-focus.mp4

Code to reproduce (note you'll need a font file called Regular.ttf in the same folder):

#!/usr/bin/env stack
{- stack 
    script 
    --resolver lts-18.25 
    --package monomer
    --package nanovg
    --package lens
    --package text
    --ghc-options=-threaded
-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}

module Main where

import Data.Text
import Control.Lens
import Monomer

newtype AppModel = AppModel { _stateText :: Text }
  deriving (Eq, Show)

data AppEvent
  = FocusTextField
  | FocusTextArea
  deriving (Eq, Show)

makeLenses 'AppModel

buildUI wenv model = widgetTree
 where
  widgetTree =
    keystroke [("C-o", FocusTextField), ("C-p", FocusTextArea)] $
      hstack
        [ textField stateText `nodeKey` "textfield"
        , textArea stateText `nodeKey` "textarea"
        ]

handleEvent wenv node model evt = case evt of
  FocusTextField -> [SetFocusOnKey "textfield"]
  FocusTextArea -> [SetFocusOnKey "textarea"]

main = do
  startApp model handleEvent buildUI config
 where
  config =
    [ appFontDef "Regular" "Regular.ttf"
    , appTheme darkTheme
    ]
  model = AppModel "changing focus with tab"

Save the code above as file and simply run with stack

stack ./Textarea.hs

I'm on Linux, if that's of any relevance.

Error when running example: glMakeCurrent

Trying to run the first tutorial example program by creating a new cabal project, adding nanovg-hs at cocreature/nanovg-hs@ba8733f and monomer at 523355c as in-tree dependencies. I also set the stb_truetype flag to true on nanovg because monomer's stack.yaml does that.

Everything compiles (with some unused-import warnings in nanovg-hs), but running the resulting executable produces the following output:

Renderer: NVIDIA GeForce GTX 1050 Ti/PCIe/SSE2
Version: 3.2.0 NVIDIA 470.57.02
test: SDLCallFailed {sdlExceptionCaller = "SDL.Video.OpenGL.glMakeCurrent", sdlFunction = "SDL_GL_MakeCurrent", sdlExceptionError = "Unable to make GL context current"}

(test is the name of the executable)

A window is created but nothing is ever drawn in it (only the window border gets drawn on my system). When I close the window, the application does print About to destroyWindow; I believe the startRenderThread thread just died, and nothing happens afterwards.

Any idea if this is a misconfiguration on my side? Can I debug this?

System:

  • Arch Linux (Linux 5.13.9) with i3
  • ghc 8.10.4, cabal 3.4.0.0

Question: Update Image Widget Source

Hello again! I had a question; I see that the library has many WidgetRequest(s) like StopTextInput, SetCursorIcon, I was wondering if one wanted to, say, update an image at the click of a button which WidgetRequest should be used?

I was about to write an UpdateImageSource WidgetId Path explicitly for this purpose but I wanted to make sure I wasn't just reinventing the wheel heh

Horizontal and vertical scroll bars are inverted

In my setup (linux, X-org) when I scroll with two fingers, the scroll bar moves in the same direction as my fingers. In windows and mac/os it is often the other way around.

However, in monomer apps it seems like the Horizontal scroll bar moves in the opposite direction. I noticed this behavior in the OpenGL example app. I checked the code and sure enough the sign is flipped between the stepX and stepY cases.

Is the sign different to get the expected behavior in some platform? I can work on this issue

Feature Request: some way to change spacing on LabeledCheckbox

Hello,

I have a checkbox in my app that looks like this:
Screenshot at 2022-01-09 21-35-39

However, I would like it to look like this (with less space between the icon and the label, to match the spacing in rest of the UI):
Screenshot at 2022-01-09 21-34-46

What do you think about adding adding a configuration option to LabeledCheckboxCfg to allow changing the spacing? It might be called childSpacing and could potentially apply to other widgets too (possibly containers like {v,h}stack?).

If you decide this makes sense, I can look into sending a PR.

Thanks!

Widget for direct backend use

I'm looking for a way of rendering part of the GUI using OpenGL, e.g; to have a 3D preview of a model embedded in a ui panel.

Perhaps a solution that is not very intrusive is to render to texture (Ideally from a shared context) and display it in Monomer.
A widget encapsulating this behavior would be ideal.

Build problem with `stack build` on x86 mac

$ git clone https://github.com/fjvallarino/monomer.git
$ cd monomer
$ stack build
Cloning ba8733f58da63e0934b5d2853ed84b71e872e6f1 from https://github.com/fjvallarino/nanovg-hs
Received ExitFailure 128 when running
Raw command: /usr/local/bin/git reset --hard ba8733f58da63e0934b5d2853ed84b71e872e6f1
Run from: /private/var/folders/qk/vw0nqkz90cz52plb04b416fh0000gn/T/with-repo49439/cloned
Standard error:

fatal: Could not parse object 'ba8733f58da63e0934b5d2853ed84b71e872e6f1'.
$

Environment:

macOS Catalina v 10.15.7

$ git --version
git version 2.33.0

$ stack --version
Version 2.7.3, Git revision 7927a3aec32e2b2e5e4fb5be76d0d50eddcc197f x86_64 hpack-0.34.4

$ brew info sdl2 glew
sdl2: stable 2.0.16 (bottled), HEAD
glew: stable 2.2.0 (bottled), HEAD

hstack problem

This might not be an issue, but I definitely ran into this and am kind of stuck:

Considering this hstack:

hstack [
        button "Back" Back,
        spacer,
        label "Mike wrote:" `styleBasic` [width 100],
        spacer,
        label "Here is something that Mike wrote"
      ] `styleBasic` [cursorHand, textTop]

The text is NOT aligned on top and the back button is huge. I tried adding styleBasic [height 20] to the back button without success.

Any help is appreciated

Screenshot_20220411_230007

test failures on macosx (on Github actions macos-latest only)

These tests passed on Linux build with Github actions, but fail when run on macosx:

Failures:

  test/unit/Monomer/Widgets/Singles/TextAreaSpec.hs:108:5: 
  1) Widgets.Singles.TextArea.handleEvent should copy and paste text around
       expected: "This long text is some long text"
        but got: "This is some long text"

  To rerun use: --match "/Widgets/Singles/TextArea/handleEvent/should copy and paste text around/"

  test/unit/Monomer/Widgets/Singles/TextAreaSpec.hs:113:5: 
  2) Widgets.Singles.TextArea.handleEvent should cut and paste text around
       expected: "This text is long"
        but got: "This is long"

  To rerun use: --match "/Widgets/Singles/TextArea/handleEvent/should cut and paste text around/"

  test/unit/Monomer/Widgets/Singles/TextAreaSpec.hs:176:5: 
  3) Widgets.Singles.TextArea.handleEventValue should input 'abc123', move to beginning, select three letters, copy, move to end, paste
       expected: TextChanged "abc123abc"
        but got: TextChanged "abc123"

  To rerun use: --match "/Widgets/Singles/TextArea/handleEventValue/should input 'abc123', move to beginning, select three letters, copy, move to end, paste/"

  test/unit/Monomer/Widgets/Singles/TextFieldSpec.hs:98:5: 
  4) Widgets.Singles.TextField.handleEvent should copy and paste text around
       expected: "This long text is some long text"
        but got: "This is some long text"

  To rerun use: --match "/Widgets/Singles/TextField/handleEvent/should copy and paste text around/"

  test/unit/Monomer/Widgets/Singles/TextFieldSpec.hs:103:5: 
  5) Widgets.Singles.TextField.handleEvent should cut and paste text around
       expected: "This text is long"
        but got: "This is long"

  To rerun use: --match "/Widgets/Singles/TextField/handleEvent/should cut and paste text around/"

  test/unit/Monomer/Widgets/Singles/TextFieldSpec.hs:161:5: 
  6) Widgets.Singles.TextField.handleEventValue should input 'abc123', move to beginning, select three letters, copy, move to end, paste
       expected: TextChanged "abc123abc"
        but got: TextChanged "abc123"

  To rerun use: --match "/Widgets/Singles/TextField/handleEventValue/should input 'abc123', move to beginning, select three letters, copy, move to end, paste/"

Randomized with seed 1908487119

How to access hidden State of widgets

Hi,

I was thinking about creating a container widget, which takes a textarea widget as input and adds line numbers.
For that I was thinking to have a look at box for the container and label as a way to display the linenumbers - but feel free to recommend other widgets I should rather have a look at.

What I was wondering is - how can the container access the internal state of textarea - specifically I want to make it possible(by cfg) for the
linenumber widget to change the color and/or font of the current line - current line refering to the y positon of the cursor in the textarea

SDL.pumpEvents seems to be required in mainLoop for Windows 10

I can't say exactly what changed on my system to cause this, but my monomer projects suddenly started hanging immediately after launch. Even reverting to older commits which I know worked or cloning monomer and building the example projects had the same behavior.

I did a bit of digging and realized that SDL.pollEvents wasn't returning anything after the first frame.

The fix ended up being a call to SDL.pumpEvents before starting the new frame in Monomer.Main.Core.mainLoop

unless shouldQuit (SDL.pumpEvents *> mainLoop window fontManager config newLoopArgs)

I'm hesitant to make a PR given that I'm not sure what exactly changed to cause this, but it is consistently reproducible.

One thought I had was the SDL2 version which is mingw-w64-x86_64-SDL2 2.0.20-1, but I'm at a bit of a loss otherwise.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.