Trying to learn to write applications with Gtk2Hs I'm getting difficulties bridging the gap between the event driven Gtk2HS and the persistent state of my model. So to simplify, lets say that I have this simple application
module Main where
import Graphics.UI.Gtk
import Control.Monad.State
main = do
initGUI
window <- windowNew
button <- buttonNew
set button [buttonLabel := "Press me"]
containerAdd window button
-- Events
onDestroy window mainQuit
onClicked button (putStrLn ---PUT MEANINGFUL CODE HERE---)
widgetShowAll window
mainGUI
and the state of my application is how many times the button has been pressed. Seeing other posts like this they rely on MVars or IORefs which do not seem satisfactory to me, because in the future maybe I will want to refactor the code so the state lives on its own context.
I think that the solution should use the State monad using a step function like:
State $ \s -> ((),s+1)
but I'm not sure about the implications, how to do that in the above code or even if that monad is the right solution to my problem.
There's basically two approaches:
Use a pointer of some kind. This is your IORef or MVar approach. You can hide this behind a MonadState-like interface if you like:
newtype GtkT s m a = GtkT { unGtkT :: ReaderT (IORef s) m a } deriving (Functor, Applicative, Monad, MonadIO)
runGtkT = runReaderT . unGtkT
instance MonadIO m => MonadState s (GtkT s m) where
get = GtkT (ask >>= liftIO . readIORef)
put s = GtkT (ask >>= liftIO . flip writeIORef s)
Pull an "inversion of control" style trick. Write a callback that prints a number, then replaces itself with a new callback that prints a higher number.
If you try to use State or StateT directly, you're gonna have a bad time.
Related
New to Go and Fyne, and stumbling trying to get what I need out of Fyne. Sorry, this will be long.
My problem is this. I’m writing a application that gets a list of commands from a server, telling it to create a series of widgets and display them. They are of various types – Label, Button, Entry, Select, etc.
But these aren’t standard widgets; I need to extend their behavior a bit. For one thing, when operated by the user, they each need access to some per-widget information. Button click, for example, has to reference some data specific to that button so it knows what to do. We’ll call this additional information the About struct.
Secondly, every widget needs to be able to take a right click and drop down a widget specific menu. Yes, even buttons and labels need to be able to provide drop down menus. In the case of a widget like Entry, I know this design is going to condemn me to having to write my own menu choices for Paste, Copy and the other operations Entry normally offers on a right click, but I’m ok with that.
I have all this working, but in the process I broke Select (and probably there will be breakage for other widgets.) and I can’t see how to fix it.
Problem: trying to send the Select widget causes a panic: interface conversion: fyne.Canvas is nil, not *glfw.glCanvas
Approach:
type GenericWidget struct {
fyne.Widget //I’m some kind of widget
about *About //here’s my personal “About” data
//function pointers
OnRightClickp func(gw *GenericWidget, pe *fyne.PointEvent)
OnLeftClickp func(gw *GenericWidget, pe *fyne.PointEvent)
…other “function pointers” for OnRunep and so on…
}
And now I have to catch all “events” so GenericWidget will see them:
func (gw *GenericWidget) TappedSecondary(pe *fyne.PointEvent) {
if (gw.OnRightClickp != nil) {gw.OnRightClickp(gw, pe)}
}
func (gw *GenericWidget) Tapped(pe *fyne.PointEvent) {
if (gw.OnLeftClickp != nil){gw.OnLeftClickp(gw, pe)}
}
//type Focusable interface
//etc….
This should represent any single widget, regardless of type. It’s not complicated: When Tapped is invoked by the driver, GenericWidget.Tapped gets called. If this widget has a function pointer for “OnLeftClickp” set, call it. Crucially, we pass a pointer to the widget itself when that happens, because all the event handlers I write will need access to the *About and maybe anything else I add to GenericWidget.
Creation is simple enough:
func NewGenericWidget(w fyne.Widget, about *About) *GenericWidget {
gw := GenericWidget{w, about, nil, nil, nil, nil, nil, nil, nil, nil}
return &gw
}
And when it’s time to create a Label, I do that and fold it into a GenericWidget
func NewExtendedLabelWithStyle( //Label with catachable left and right click
text string,
about *About,
alignment fyne.TextAlign,
style fyne.TextStyle,
tappedLeft func(*GenericWidget, *fyne.PointEvent),
tappedRight func(*GenericWidget, *fyne.PointEvent)) *GenericWidget {
e := NewGenericWidget(widget.NewLabelWithStyle(text, alignment, style), about)
e.OnLeftClickp = tappedLeft
e.OnRightClickp = tappedRight
return e
}
All these GenericWidgets work fine – I add them to the appropriate Box and the window paints as I’d expect. I can right click on a label and if OnRightClickp is set, which is generally is, code gets called and is given access to *GenericWidget, which leads to *About, which means the menu that gets put up can offer all the right stuff for what’s in this label.
Of course, Labels don’t normally care about clicking, so the fact that I’ve stolen all the calls in Tappable doesn’t matter.
But a Select widget does care about left clicks, so the fact that GenericWidget is intercepting the call to Tapped() means I’d never see the dropdown appear.
No problem, I thought. When I create the Select widget and the surrounding GenericWidget, I’ll just specify I want to call Select’s Tapped myself:
func NewExtendedSelect(about *About, sel func(*GenericWidget, string)) *GenericWidget {
//build the options. NewSelect demands a slice of strings, so...
st := make([]string, 64)
for e := about.theList.Front(); e != nil; e = e.Next() {
st = append(st, e.Value.(string))
}
s := widget.NewSelect(st, func(c string){})
//make sure it selects the text it should, initially
s.SetSelected(about.value)
//wrap it
e := NewGenericWidget(s, about)
//e.OnChangedp = sel //not set up yet (and don’t know how)
//HERE BE DRAGONS --------------
//But we don't want to break left click. So when we intercept it,
// pass it down to the actual Selection widget:
e.OnLeftClickp = func(me* GenericWidget, pe *fyne.PointEvent) {
fmt.Println("select tapped")
//call the Tapped that Select knows about:
s.Tapped(pe) //PANIC!
}
// -----------------------------
//Handle right click with our usual menu magic
e.OnRightClickp =func(me* GenericWidget, pe *fyne.PointEvent) {
//defer used because not sure what to do with the return value, so make it Go's problem
defer widget.NewPopUpMenuAtPosition(me.GetRightClickMenu(),
me.about.sheet.window.Canvas(), pe.AbsolutePosition)
}
return e //here's your GenericWidget, ready to drop into a Fyne container.
}
Compiles fine, Selects get displayed, but when I left click it prints the expected “select tapped” and then immediately panics:
select tapped
panic: interface conversion: fyne.Canvas is nil, not *glfw.glCanvas
I’m lost. My GenericWidget is just a widget; I thought that’s what composition did, and all the GenericWidgets I create are put in a Box which is in a Box which is SetContent into the window. But the error is suggesting to me that somehow this Select object wasn’t set up right and when it goes to draw the options, something is missing. What did I do wrong?
It’s possible my whole approach is wrong (I do a lot of C++ and Python and I take an OO view of things). In that case, how do I do all this?
This turns out to have been a Fyne bug, which has since been fixed.
It does not look like the select is being composed - your extended select is just creating a new one, tapping it later.
The crash is coming from it trying to display a pop up next to a select that has not been found on the canvas.
If you are extending builtin widgets you also need to call ExtendBaseWidget so that the driver can lookup your widget instead of the default one.
That said a single widget that can extend any other type of widget kind of goes against the strongly types design of Fyne APIs and you may run in to trouble.
I'm wandering if this is the optimal way of doing it with ScalaFx: A GUI is composed of bunch of nodes, to which I suck content from a SQL-DB. Main Pane is a FlowPane populated with few hundred elements. Each element is composed of four level hierarchy (see numbers describing the levels):
1 2 3 4
VBox -+-> VBox ---> StackPane -+-> ImageView
+-> Label +-> Rectangle
As far as I have experienced the I can access the nodes and their attributes in different levels. Ie. I can give user feedback by changing the Rectangle color below the ImageView Node as the compound element is chosen by mouse click or by ContextMenu.
I could access the Rectangle attributes directly, but it is easy to make mistakes as the list references children.get(0) are directly dependent from order of the children as the nodes are positioned in parent.
val lvone = vbnode.children // VBox (main)
val lvtwo = lvone.get(0) // VBox
val lvthree = lvtwo.asInstanceOf[javafx.scene.layout.VBox].children.get(0) // StackPane
val lvfour = lvthree.asInstanceOf[javafx.scene.layout.StackPane].children.get(0) // Rectangle
if (lvfour.isInstanceOf[javafx.scene.shape.Rectangle]) lvfour.asInstanceOf[javafx.scene.shape.Rectangle].style = "-fx-fill: #a001fc;"
println("FOUR IS:"+lvfour.getClass)
Here's sample to demonstrate the "safer" access to the elements in node hierarchy (node hierarchy creation is in rather annoying structure of code, so it is not included):
val levelone = vbnode.children
println("LV1 Node userData:"+vbnode.userData) // my database reference for the main / container element
println("LV1 Parent children class:"+levelone.get(0).getClass) // class javafx.scene.layout.VBox
for (leveltwo <- levelone) {
println("LV2 Children Class:"+leveltwo.getClass)
println("LV2 Children Class Simple Name:"+leveltwo.getClass.getSimpleName) // VBox
if (leveltwo.getClass.getSimpleName == "VBox") {
leveltwo.style = "-fx-border-width: 4px;" +
"-fx-border-color: blue yellow blue yellow;"
for (levelthree <- leveltwo.asInstanceOf[javafx.scene.layout.VBox].children) {
println("LV3 children:"+levelthree.getClass.getName)
if (levelthree.getClass.getSimpleName == "StackPane") {
for (levelfour <- levelthree.asInstanceOf[javafx.scene.layout.StackPane].children) {
println("LV4 children:"+levelfour.getClass.getName)
if (levelfour.getClass.getSimpleName == "Rectangle") {
if (levelfour.isInstanceOf[javafx.scene.shape.Rectangle]) println("Rectangle instance confirmed")
println("LV4 Found a Rectangle")
println("original -fx-fill / CSS:"+ levelfour.asInstanceOf[javafx.scene.shape.Rectangle].style)
levelfour.asInstanceOf[javafx.scene.shape.Rectangle].style = "-fx-fill: #a001fc;"
} // end if
} // end for levelfour
} // end if
} // end for levelthree
} // end if
} // end for leveltwo
Questions:
Is there smarter way to do the type casting of node types, since only javafx API based references are acceptable (BTW I'm using ScalaIDE)? Options I am using are:
1- simple / shortcut way: evaluation by using leveltwo.getClass.getSimpleName == "VBox" , which is the shortcut from API jungle. But is it efficient and safe?
2- cluttering way by using probably the by the book style:
if (levelfour.isInstanceOf[javafx.scene.shape.Rectangle])
Other question: Now in reference to the fully qualified reference based on javafx ie. javafx.scene.shape.Rectangle, I would like to use scala reference instead, but I get an error which enforces me to adopt the javafx based reference. Not a big deal as I can use javafx reference, but I wander if there is scalafx based option?
Happy to get constructive feedback.
If I understand you correctly, you seem to be wanting to navigate the nodes of a sub-scene (that belongs to a higher-level UI element construct) in order to change the appearance of some of the nodes within it. Do I have that right?
You raise a number of different issues, all within the one question, so I'll do my best to address them all. As a result, this is going to be a long answer, so please bear with me. BTW, In future, it would help if you ask one question for each issue. ;-)
Firstly, I'm going to take your problem at face value: that you need to browse through a scene in order to identify a Rectangle instance and change its style. (I note that your safe version also changes the style of the second VBox, but I'm going to ignore that for the sake of simplicity.) This is a reasonable course of action if you have little to no control over the structure of each element's UI. (If you directly control this structure, there are far better mechanisms, which I'll come to later.)
At this point, it might be worth expanding on the relationship between ScalaFX and JavaFX. The former is little more than a set of wrappers for the latter, to give the library a Scala flavor. In general, it works like this: the ScalaFX version of a UI class takes a corresponding JavaFX class instance as an argument; it then applies Scala-like operations to it. To simplify things, there are implicit conversions between the ScalaFX and JavaFX instances, so that it (mostly) appears to work by magic. However, to enable this latter feature, you must add the following import to each of your source files that reference ScalaFX:
import sclafx.Includes._
For example, if JavaFX has a javafx.Thing (it doesn't), with setSize and getSize accessor methods, then the ScalaFX version would look like this:
package scalafx
import javafx.{Thing => JThing} // Rename to avoid confusion with ScalaFX Thing.
// ScalaFX wrapper for a Thing.
class Thing(val delegate: JThing) {
// Axilliary default constructor. Let's assume a JThing also has a default
// constructor.
//
// Creates a JavaFX Thing when we don't have one available.
def this() = this(new JThing)
// Scala-style size getter method.
def size: Int = delegate.getSize
// Scala-style size setter method. Allows, say, "size = 5" in your code.
def size_=(newSize: Int): Unit = delegate.setSize(newSize)
// Etc.
}
// Companion with implicit conversions. (The real implementation is slightly
// different.)
object Thing {
// Convert a JavaFX Thing instance to a ScalaFX Thing instance.
implicit def jfxThing2sfx(jThing: JThing): Thing = new Thing(jThing)
// Convert a ScalaFX Thing instance to a JavaFX Thing instance.
implicit def sfxThing2jfx(thing: Thing): JThing = thing.delegate
}
So, quite a lot of work for very little gain, in all honesty (although ScalaFX does simplify property binding and application initialization). Still, I hope you can follow me here. However, this allows you to write code like the following:
import javafx.scene.shape.{Rectangle => JRectangle} // Avoid ambiguity
import scalafx.Includes._
import scalafx.scene.shape.Rectangle
// ...
val jfxRect: JRectangle = new JRectangle()
val sfxRect: Rectangle = jfxRect // Implicit conversion to ScalaFX rect.
val jfxRect2: JRectangle = sfxRect // Implicit conversion to JavaFX rect.
// ...
Next, we come to type checking and casting. In Scala, it's more idiomatic to use pattern matching instead of isInstanceOf[A] and asInstanceOf[A] (both of which are frowned upon).
For example, say you have a Node and you want to see if it is actually a Rectangle (since the latter is a sub-class of the former). In the style of your example, you might write something like the following:
def changeStyleIfRectangle(n: Node): Unit = {
if(n.isInstanceOf[Rectangle]) {
val r = n.asInstanceOf[Rectangle]
r.style = "-fx-fill: #a001fc;"
}
else println("DEBUG: It wasn't a rectangle.")
}
The more idiomatic Scala version of the same code would look like this:
def changeStyleIfRectangle(n: Node): Unit = n match {
case r: Rectangle => r.style = "-fx-fill: #a001fc;"
case _ => println("DEBUG: It wasn't a rectangle.")
}
This may seem a little finicky, but it tends to result in simpler, cleaner code, as I hope you'll see. In particular, note that case r: Rectangle only matches if that is the real type of n, and it then casts n to r as a Rectangle.
BTW, I would expect that comparing types is more efficient than getting the name of the class, via getClass.getSimpleName and comparing to a string, and there's less chance of error. (For example, if you mistype the class name of the string you're comparing to, e.g. "Vbox", instead of "VBox", then this will not result in a compiler error, and the match will always fail.)
As you point out, your direct approach to identifying the Rectangle is limited by the fact that it requires a very specific scene structure. If you change how each element is represented, then you must change your code accordingly, or you'll get a bunch of exceptions.
So let's move on to your safe approach. Clearly, it's going to be a lot slower and less efficient than the direct approach, but it still relies upon the structure of the scene, even if it's less sensitive to the order in which the children are added at each level of hierarchy. If we change the hierarchy, it will likely stop working.
Here's an alternative approach that uses the class hierarchy of the library to assist us. In a JavaFX scene, everything is a Node. Furthermore, nodes that have children (such as VBox and StackPane) are subclasses of Pane as well. We'll use a recursive function to browse the elements below a specified starting Node instance: every Rectangle it encounters will have its style changed.
(BTW, in this particular case, there are some issues with implicit conversions, which makes a pure ScalaFX solution a little cumbersome, so I'm going to match directly on the JavaFX versions of the classes instead, renamed to avoid any ambiguity with the equivalent ScalaFX types. The implicit conversions will work fine when calling this function.)
import javafx.scene.{Node => JNode}
import javafx.scene.layout.{Pane => JPane}
import javafx.scene.shape.{Rectangle => JRectangle}
import scala.collection.JavaConverters._
import scalafx.Includes._
// ...
// Change the style of any rectangles at or below starting node.
def setRectStyle(node: JNode): Unit = node match {
// If this node is a Rectangle, then change its style.
case r: JRectangle => r.style = "-fx-fill: #a001fc;"
// If the node is a sub-class of Pane (such as a VBox or a StackPane), then it
// will have children, so apply the function recursively to each child node.
//
// The observable list of children is first converted to a Scala list to simplify
// matters. This requires the JavaConverters import above.
case p: JPane => p.children.asScala.foreach(setRectStyle)
// Otherwise, just ignore this particular node.
case _ =>
}
// ...
A quick few observations on this function:
You can now use any hierarchy of UI nodes that you like, however, if you have more than one Rectangle node, it will change the style of all of them. If this doesn't work for you, you could add code to check other attributes of each Rectangle to determine which one to modify.
The asScala method is used to convert the children of the Pane node to a Scala sequence, so we can then use the foreach higher-order function to recursively pass each child in turn to the setRectStyle method. asScala is made available by the import scala.collection.JavaConverters._ statement.
Because the function is recursive, but the recursive call is not in the tail position (the last statement of the function), it is not tail-recursive. What this means is if you pass a huge scene to the function, you might get a StackOverflowException. You should be fine with any reasonable size of scene. (However, as an exercise, you might want to write a tail-recursive version so that the function is stack safe.)
This code is going to get slower and less efficient the bigger the scene becomes. Possibly not your top concern in UI code, but a bad smell all the same.
So, as we've seen, having to browse through a scene is challenging, inefficient and potentially error prone. Is there a better way? You bet!
The following will only work if you have control over the definition of the scene for your data elements. If you don't, you're stuck with solutions based upon the above.
The simplest solution is to retain a reference to the Rectangle whose style you want to change as part of a class, then access it directly as needed. For example:
import scalafx.Includes._
import scalafx.scene.control.Label
import scalafx.scene.layout.{StackPane, VBox}
import scalafx.scene.shape.Rectangle
final class Element {
// Key rectangle whose style is updated when the element is selected.
private val rect = new Rectangle {
width = 600
height = 400
}
// Scene representing an element.
val scene = new VBox {
children = List(
new VBox {
children = List(
new StackPane {
children = List(
// Ignore ImageView for now: not too important.
rect // Note: This is the rectangle defined above.
)
}
)
},
new Label {
text = "Some label"
}
)
}
// Call when element selected.
def setRectSelected(): Unit = rect.style = "-fx-fill: #a001fc;"
// Call when element deselected (which I assume you'll require).
def setRectDeselected(): Unit = rect.style = "-fx-fill: #000000;"
}
Clearly, you could pass a data reference as an argument to the class and use that to populate the scene as you like. Whenever you need to change the style, calling one of the two latter functions achieves what you need with surgical precision, no matter what the scene structure looks like.
But there's more!
One of the truly great features about ScalaFX/JavaFX is that it has observable properties that can be used to make the scene manage itself. You will find that most fields on a UI node are of some type "Property". What this allows you to do is to bind a property to the field, such that when you change the property, you change the scene accordingly. When combined with event handlers, the scene takes care of everything all by itself.
Here, I've reworked the latter class. Now, it has a handler that detects when the scene is selected and deselected and reacts by changing the property that defines the style of the Rectangle.
import scalafx.Includes._
import scalafx.beans.property.StringProperty
import scalafx.scene.control.Label
import scalafx.scene.input.MouseButton
import scalafx.scene.layout.{StackPane, VBox}
import scalafx.scene.shape.Rectangle
final class Element {
// Create a StringProperty that holds the current style for the Rectangle.
// Here we initialize it to be unselected.
private val unselected = "-fx-fill: #000000;"
private val selected = "-fx-fill: #a001fc;"
private val styleProp = new StringProperty(unselected)
// A flag indicating whether this element is selected or not.
// (I'm using a var, but this is heavily frowned upon. A better mechanism might be
// required in practice.)
private var isSelected = false
// Scene representing an element.
val scene = new VBox {
children = List(
new VBox {
children = List(
new StackPane {
children = List(
// Ignore ImageView for now: not too important.
// Key rectangle whose style is bound to the above property.
new Rectangle {
width = 600
height = 400
style <== styleProp // <== means "bind to"
}
)
}
)
},
new Label {
text = "Some label"
}
)
// Add an event handler. Whenever the VBox (or any of its children) are
// selected/unselected, we just change the style property accordingly.
//
// "mev" is a "mouse event".
onMouseClicked = {mev =>
// If this is the primary button, then change the selection status.
if(mev.button == MouseButton.Primary) {
isSelected = !isSelected // Toggle selection setting
styleProp.value = if(isSelected) selected
else unselected
}
}
}
}
Let me know how you get on...
can anybody help me achieving this with luakit?
I'm running raspbian on rpi3 and for my application I need one luakit window constantly running in full screen mode and triggered by a bash script, I want another browser window open from time to time in a certain size e.g. 800x600. Would be nice if I could also determine the position of the second window.
I was able to launch luakit in full screen or specific size by overwriting the window function in my rc.lua config. I then launch luakit with either the one or the other rc.lua file (-c parameter) . However if one instance of luakit is already running, the second luakit window uses the config of the first one that is already running.
Can I somehow trigger the window size of a new luakit window from bash script?
Thanks for any help.
I found a solution to my problem: instead of giving the browser instance the window size, I let itself decide whether or not to launch in fullscreen by checking the URL.
in my rc.lua I added require "userconf" and created a file userconf.lua in which I have overwritten the function window.new like so:
function window.new(uris)
local w = window.build()
-- Set window metatable
setmetatable(w, {
__index = function (_, k)
-- Check widget structure first
local v = rawget(w, k)
if v then return v end
-- Call each window index function
for _, index in ipairs(window.indexes) do
v = index(w, k)
if v then return v end
end
end,
})
-- Setup window widget for signals
lousy.signal.setup(w)
-- Call window init functions
for _, func in pairs(window.init_funcs) do
func(w)
end
-- Call window init functions
for _, func in pairs(window.init_funcs) do
func(w)
end
-- Populate notebook with tabs
for _, uri in ipairs(uris or {}) do
w:new_tab(w:search_open(uri), false)
end
-- Make sure something is loaded
if w.tabs:count() == 0 then
w:new_tab(w:search_open(globals.homepage), false)
end
-- Set initial mode
w:set_mode()
-- Show window
w.win:show()
-- we check the url, if it points to the URL i want to see in fullscreen we launch in fullscreen otherwise we leave the default.
-- open myapplication.html in fullscreen, every other window in normal mode
w.win.fullscreen = false
for _, uri in ipairs(uris or {}) do
if string.match(uri, "myapplication.html") then
print "got myapplication.html"
w.win.fullscreen = true
end
end
return w
end
It's probably not a 100% solution, but for me it's ok
How do I listen to MouseMove event, only after I have pressed my mouse button (MouseDown event)
Im basicly looking for Click->Drag->Release functionality in a F# forms application
This behavior can be nicely captured using the F# async workflows mechanism. I wrote an article about this (implementing exactly drag & drop kind of functionality) where you can find the details - See Programming user interfaces with F# async workflows.
The sample application implements drawing where you push a button, then move the mouse (to define a rectangle) and then eventually release the button:
let rec drawingLoop(clr, from) = async {
// Wait for the first MouseMove occurrence
let! move = Async.AwaitObservable(form.MouseMove)
if (move.Button &&& MouseButtons.Left) = MouseButtons.Left then
// Refresh the window & continue looping
drawRectangle(clr, from, (move.X, move.Y))
return! drawingLoop(clr, from)
else
// Return the end position of rectangle
return (move.X, move.Y) }
let waitingLoop() = async {
while true do
let! down = Async.AwaitObservable(form.MouseDown)
let downPos = (down.X, down.Y)
if (down.Button &&& MouseButtons.Left) = MouseButtons.Left then
let! upPos = drawingLoop(Color.IndianRed, downPos)
do printfn "Drawn rectangle (%A, %A)" downPos upPos }
The nice thing here is that you can pretty nicely express the logic - wait for MouseDown (inside waitingLoop), then call the drawingLoop function which waits for MouseMove until the button is released (and then transfers the control back to waitingLoop which starts waiting for another mouse down event).
Another version of a similar piece of code is in Phil Trelford's fractal zoom, which uses the same gesture for zooming.
The complete source code is a part of the Chapter 16 source code of Real-World Functional Programming.
Attach the event listeners for move and up in the mouse down event, remove it in the up. This does mean the handler method needs to be a method (or you need to keep hold of the delegate used) to pass to the event's remove method.
(If this were for C# I would point you towards Rx—the Reactive Extensions—as this is perhaps the defining example, but I'm unsure how well Rx works with F#.)
You can also use something like this:
let setupDrag(target, fn) =
let isDown = ref false
target.MouseDown |> Event.add(fun _ -> isDown := true)
target.MouseMove |> Event.filter(fun _ -> !isDown) |> Event.add(fn)
target.MouseUp |> Event.add(fun( _ -> isDown := false)
In a real implementation, you may want to actually do other stuff when the transition starts, stops, and all those things. You may for example want to capture the pointer on target.
I'm trying to show a window in xcb, inside the main window, but actually without luck.
The idea is that when the user press a button (in that case the X button) a small white window is shown (just for test).
But actually i'm stuck on that step. I watched the example code here:
http://en.wikibooks.org/wiki/X_Window_Programming/XCB
And tried to do the same in my application.
[EDIT 28/10/2013] Now with that code i can show a window, but if i try to add other variable like int i=0, or whatever, the window doesn't appear, and no expose events were raised (all events that were raised are or 0 or 2 (even if i add the variables inside other events). Any idea?
This is the XCB_KEY_PRESS event handler code:
Edit (with the new code)
case XCB_KEY_PRESS:{
xcb_key_press_event_t *kp = (xcb_key_press_event_t *)ev;
if(kp->detail==53){
printf("X pressed\n");
uint32_t vals[2];
mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
vals[0]=screen->white_pixel;
vals[1]=XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS;
win = xcb_generate_id(connection);
xcb_create_window(
connection,
XCB_COPY_FROM_PARENT,
win,
root,
80,80,
150,150,
10,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
screen->root_visual,
mask, values);
mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
vals[0]=screen->white_pixel;
vals[1]=0;
background=xcb_generate_id(connection);
xcb_create_gc(connection, background, win, mask, vals);
xcb_map_window(connection,win);
xcb_flush(connection);
printf("finished\n");
}
printf("KEY_PRESS - Pressed: %d\n", kp->detail);
}
root is the root window obtained from xcb_screen_t variable.
The definition of background and win are the following:
xcb_window_t win;
xcb_gcontext_t background;
And i added even a XCB_EXPOSE event handler:
case XCB_EXPOSE:{
printf("EXPOSE NEW WINDOW CREATED\n");
xcb_poly_fill_rectangle(connection, win, background,1,&rectangle);
xcb_flush(connection);
}
What is wrong with that code? What am i missing? (I'm trying to develop a very basic window manager, just for fun)
(My idea for that program is that when x is pressed an input box is shown, do you have any suggestion on how to do that?)