I have a program which performs a long-going calculation where the result is shown as a plot.
I am currently using Chart-0.14 for this. I want to show the partial results, and update during calculations.
Graphics.Rendering.Chart.Gtk.updateCanvas :: Renderable a -> DrawingArea -> IO Bool seems to do that, but I do not find any way to get a DrawingArea from the plot. The function renderableToWindow :: Renderable a -> Int -> Int -> IO () does not return anything (and furthermore it does not return before the window is closed).
I would like to do something like the following:
main = do
drawingArea = forkRenderableToWindow (toRenderable $ plotLayout $
plot [0,0.1..10] sin "sin(x)") 640 480
updateCanvas (toRenderable $ plotLayout $ plot [0,0.1..10] sin "sin(x)") drawingArea
How should I do this? Would I need to reimplement the functions in Graphics.Rendering.Chart.Gtk with a version that returns the DrawingArea and in some way (how would I do this? forkIO?) returns immediately without closing the window?
You are looking for createRenderableWindow and then you need to use the GTK operations to work on the given Window - I don't think the Chart package exports any higher level operations on Windows.
EDIT2: So ignore the below - it doesn't work even with GUI initilization. My comment was a guess based on types.
EDIT:
Here is some example code. Understand, I'm just piecing things together based on the types. There might be better ways to do things if you ask someone who actually knows the library.
Below we use:
createRenderableWindow - this was the crux of my answer
castToDrawingArea - This is needed to get a DrawingArea from the Window type provided by GTK. These casts are taking place of C++ OO inheritance, I think.
widgetShowAll - because we haven't actually displayed the window, we best do that. I stole this function after looking at the source for renderableToWindow.
updateCanvas - I just saw this in the haddock documentation and figured it is why you wanted a DrawingArea in the first place.
Now for the code:
import Graphics.Rendering.Chart.Gtk
import Graphics.Rendering.Chart.Renderable
import Graphics.UI.Gtk.Misc.DrawingArea
import qualified Graphics.UI.Gtk as G
main = do
win <- createRenderableWindow emptyRenderable 400 400
let draw = castToDrawingArea win
G.widgetShowAll win
updateCanvas emptyRenderable draw
Related
I'm making an Asteroids clone in Haskell using Gloss.
I want the spaceship to come back from the left if it goes out on the right side of the screen.
This is made unnecessarily tricky by the fact that the origin (0, 0) is in the middle of the screen.
Is there a way to move the origin to the top (or bottom) left?
My Main module (where I'm interacting with Gloss) looks like this:
module Main where
import Graphics.Gloss (Display (InWindow), black, play)
-- my own imported code
import Assets (loadAssets)
import GameState (defaultHeight, defaultWidth, initGameState)
import HandleInput (handleInput)
import ProgressGameState (progressGameState)
import Render (render)
windowDisplay :: Display
windowDisplay = InWindow "Window" (defaultWidth, defaultHeight) (10, 10)
main :: IO ()
main = do
assets <- loadAssets
play
windowDisplay
black
60
initGameState
(render assets)
handleInput
progressGameState
I don't think there's an easy way to move the origin. But the conversion between whatever your format is a simple translation. You can use a function (or even a smart constructor) to do the calculation between the two.
For example, if (0,0) is at the center of a picture with the dimensions (x,y), but you would want it to be at the top left, all you have to do is substract (x/2,y/2) from all your points to make the math right again.
I am learning how to use the Gloss library to make some animations in Haskell.
Consider the code below which animates a circle that shrinks and expands its radius with time.
import Graphics.Gloss
import Graphics.Gloss.Interface.Pure.Game
type Radius = Float
type RealTime = Float
data World = World Radius RealTime
main :: IO ()
main
= do let initWorld = World 100.0 0
let windowSize = (800,800)
let windowPosition = (200,200)
putStrLn "Before play"
play (InWindow "Wobbling Circle" windowSize windowPosition)
white 40 initWorld renderWorld handleEvent stepWorld
putStrLn "After play"
renderWorld :: World -> Picture
renderWorld (World rad rtime ) = Pictures [ Circle rad ]
handleEvent :: Event -> World -> World
handleEvent _ = id
stepWorld :: Float -> World -> World -- wobbling circle
stepWorld _ (World _ rtime) = World (100 * sin rtime) (rtime+0.1)
I compiled this code with ghc --make -O2 -threaded Main.hs on an Ubuntu 14.04 machine.
When I run the code, the "Before play" statement is printed out and then the animation starts as expected. However, when I close the animation window, the code terminates immediately without printing the "After Play" statement. Why is that?
Presumably you are using the GLUT backend (the default). Take a look at some of the source code for gloss (exactly as it appears with comments):
instance Backend GLUTState where
initBackendState = glutStateInit
initializeBackend = initializeGLUT
-- non-freeglut doesn't like this: (\_ -> GLUT.leaveMainLoop)
exitBackend = (\_ -> System.exitWith System.ExitSuccess)
....
When it exits the main loop, gloss will call exitBackend, whatever it is. For GLUT, that simply calls System.exitWith which naturally will terminate your program. The more sensible thing to do would be to call leaveMainLoop but as the comment in the code says, implementations of glut other than freeglut don't work well with that function (why? who knows. This is what the authors of gloss claim).
Your potential solutions are to use freeglut specifically and modify the source code of gloss to change exitBackend; or use the GLFW backend, which doesn't have this problem.
I've been reading the source code of the Haskell Chart package as I find the charts it creates are very good. But I'm stumped on how it works.
In particular, there is a type PickFn that is used by the render function:
type PickFn a = Point -> Maybe a
data Renderable a = Renderable {
minsize :: ChartBackend RectSize,
render :: RectSize -> ChartBackend (PickFn a)
}
class ToRenderable a where
toRenderable :: a -> Renderable ()
Commentary for PickFn is "A function that maps a point in device coordinates to some value." which unfortunately doesn't mean anything to me.
My ultimate goal is to be able to follow the code to learn how it draws its charts, but I'd like to start with "what is a pick function" so that I can at least understand the types.
The pick function is a convenience to the client of the Chart library - it lets you map back from a point in the resulting image to the thing (that's the Maybe a) at that position.
For example, Graphics.Rendering.Chart.Layout.layoutToRenderable returns a Renderable (LayoutPick x y y) so that you can map back from a point in the picture back to a specific component of the layout - its legend, an axis title, the plot area, etc.
Using the gnuplot module, after I plot a graph I get put into the gnuplot console. Is there a way to stop this happening? I never use it, and it's annoying to have to type exit after closing each graph, especially when I'm testing a sequence of plots.
For example:
module Main where
import Graphics.Gnuplot.Simple
main = do
let xs = linearScale 100 (-10, 10) :: [Float]
plotFunc [] xs sin
plotFunc [] xs cos
I'm using Windows 7 x64 and the Haskell Platform 2013.2.0.0 if that makes a difference.
Try the following:
bind Close "exit gnuplot"
It should do the trick!
See here for bind details if you aren't familiar: bind reference
I have a DrawingArea onto which I can draw using primitives such as drawRectangle and drawLine. How do I draw text onto that area? I'm most interested in something that quickly outputs a single line of text.
Graphics.UI.Gtk.Gdk.Drawable.layoutLine seems to be what I want, but it wants a Graphics.Rendering.Pango.Layout.LayoutLine as input. How do I construct that LayoutLine?
Are there better alternatives than doing it this way?
Thanks!
I don't know if you would consider using Cairo. If so, I think the function showText may be what you are looking for. Use the cairo function moveTo to move to a specific location before writing the text. This is one of the simplest working examples I can produce:
import Graphics.UI.Gtk
import Graphics.Rendering.Cairo
main :: IO ()
main = do
initGUI
window <- windowNew
drawingArea <- drawingAreaNew
containerAdd window drawingArea
drawingArea `onExpose` (\_ -> renderScene drawingArea)
window `onDestroy` mainQuit
windowSetDefaultSize window 640 480
widgetShowAll window
mainGUI
renderScene :: DrawingArea -> IO Bool
renderScene da = do
dw <- widgetGetDrawWindow da
renderWithDrawable dw $ do setSourceRGBA 0.5 0.5 0.5 1.0
moveTo 100.0 100.0
showText "HelloWorld"
return True
I found the following to be an excellent guide, even though it was not for Haskell:
http://zetcode.com/tutorials/cairographicstutorial/cairotext/
I've found the way to do this with Pango.
layout <- widgetCreateLayout drawAreaWidget stringToDraw
Then you can use this newly-created layout with functions such as drawLayout and drawLayoutWithColors.