I've made an Area mesh and collision shape in it (it's a 3D simple square):
Then in the Area "barillet", I'm detecting the touch:
extends Area
func _input_event(camera, event, position, normal, shape_idx):
if event is InputEventScreenTouch:
print("touch : ", event, " -> ", event.is_pressed())
I've changed my settings so that the mouse emulates the ScreenTouch, and everything works fine: when I click on the Area, I see in the log: touch : [InputEventScreenTouch:1463] -> True. And this means event.is_pressed()==True.
If I release while in the Area it works: I see in the log: touch : [InputEventScreenTouch:1487] -> False
If I release outside the Area nothing happens.
How do I detect it's been released outside the Area?
You can get input events outside of the Area in _input. Use that to get the release:
func _input(event: InputEvent) -> void:
if (
event is InputEventScreenTouch
and not event.is_pressed()
):
print("released")
However, you would only want to get that after you got the press, right? So, let us disable _input on _ready and on _input, and enable it on _input_event:
extends Area
func _ready():
set_process_input(false)
func _input_event(camera: Object, event: InputEvent, position: Vector3, normal:Vector3, shape_idx:int) -> void:
if (
event is InputEventScreenTouch
and event.is_pressed()
):
print("picked")
set_process_input(true)
func _input(event: InputEvent) -> void:
if (
event is InputEventScreenTouch
and not event.is_pressed()
):
print("released")
set_process_input(false)
That should do the trick.
Addendum: Being this for touch, you may want to also remember index, for multi-touch support:
extends Area
var drag_index := -1
func _ready():
set_process_input(false)
func _input_event(camera: Object, event: InputEvent, position: Vector3, normal:Vector3, shape_idx:int) -> void:
if (
event is InputEventScreenTouch
and event.is_pressed()
):
print("picked")
drag_index = (event as InputEventScreenTouch).index
set_process_input(true)
func _input(event: InputEvent) -> void:
if (
event is InputEventScreenTouch
and (event as InputEventScreenTouch).index == drag_index
and not event.is_pressed()
):
drag_index = -1
print("released")
set_process_input(false)
I'll also mention that you could handle InputEventScreenDrag for drag, but if you only care about release, that is not necesary.
Related
I'm trying to use an animation for a sudoku app. I want for everytime i insert a wrong number, that number would change color and it's scale.
My code is:
override fun onDraw(canvas: Canvas?) {
canvas ?: return
drawBoard(canvas)
drawNumberProblem(canvas)
}
private fun drawNumberProblem(canvas: Canvas){
paint.color=darkcolor
paint.textSize = cellSide*3/4
SudokuGame.numbersproblem.forEach { e->
canvas.drawText("${e.number}", originX + e.col * cellSide+cellSide/5, originX + (e.row+1) * cellSide-cellSide/10, paint)
}
}
And i tried:
private fun initAnimation() {
var animation = RotateAnimation(0f, 360f, 150f, 150f)
animation.setRepeatCount(Animation.INFINITE)
animation.setRepeatMode(Animation.RESTART)
animation.setDuration(7500L)
animation.interpolator = LinearInterpolator()
startAnimation(animation)
}
override fun onDraw(canvas: Canvas?) {
canvas ?: return
if(animation==null)
initAnimation()
drawBoard(canvas)
drawNumberProblem(canvas)
}
private fun drawNumberProblem(canvas: Canvas){
paint.color=darkcolor
paint.textSize = cellSide*3/4
SudokuGame.numbersproblem.forEach { e->
canvas.drawText("${e.number}", originX + e.col * cellSide+cellSide/5, originX + (e.row+1) * cellSide-cellSide/10, paint)
}
}
The animation, the board and the numbers are all good. The animation is only an example, i tried to rotate it to see if it's working. But the only problem is that the animation is working for the whole board, i want to have animation only over numbers.
Is there any way to create a initAnimation with a parameter like initAnimation(drawNumberProblem())?
I am new to kotlin animation, so i don't really care about the best way to do it, i want to find a simple way to understand it.
Thanks
If each cell is its own View (say a TextView) you can animate it the way you're trying to, and the animation framework will take care of the timing, the rotation and scaling, etc. Because each view is separate, they can all be animated independently, using Android's view animation libraries, and a lot of the work is taken care of for you - it's pretty easy to use!
If it's all one view, and you're drawing a bunch of elements which can all be animated, you have to keep track of those elements, any animations that should be happening to each one, and how each animation's state affects the element when it comes time to draw it. Instead of each view having its own state and being drawn separately, you have to draw the whole thing at once, because it's a single view. So you need to keep track of those individual element states yourself, so you can refer to them when drawing the current overall state.
So for example, say you've got an animation where an element needs to scale to 2x the size and then back to normal, and it runs for 1 second total (1000ms). When you come to draw that element, you need to know how far along that animation you are at that moment, so you can scale it appropriately, and draw it at the correct size.
There are lots of ways to do this, probably some smarter ones, but this is the most basic hands-on example I think. I'm not testing this, but hopefully it gives you the idea:
// for brevity, so we can just say "now" instead of writing out the whole function call
val now: Long get() = System.currentTimeMillis()
// store a start time for each grid cell (or null if there's no anim running)
val animStartTimes = Array(CELL_COUNT)<Long?>
val animLength = 1000 // millis
// Basic function to start an animation - you could adapt this to prevent restarts
// while an anim is already running, etc
fun startAnim(cellIndex: Int) {
animStartTimes[cellIndex] = now
// tell the view it needs to redraw (since we're animating something now)
invalidate()
}
// Get the current progress of an animation in a cell, from 0% to 100% (0.0 to 1.0)
// I'm treating a finished item as "reset" to its original state
fun getAnimProgress(cellIndex: Int): Float {
val start = animStartTimes[cellIndex]
if (start == null) return 0f
val progress = (now - start) / animLength
if (progress > 1f) {
// animation has ended (past 100% of its runtime) so let's clear it
animStartTimes[cellIndex] = null
return 0f // like I said, I'm treating finished animations as "reset" to 0%
} else return progress
}
override fun onDraw(canvas: Canvas) {
// this flag can be set to true if we find an element that's still animating,
// so we can decide whether to call invalidate() again (forcing a redraw next frame)
var animating = false
items.forEachIndexed { i, item ->
val animProgress = getAnimProgress(i)
if (animProgress > 0f) animating = true // set that flag
// now you need to use that 0.0-1.0 value to calculate your animation state,
// e.g. adjusting the text size by some factor - 0.0 should produce your "default" state
}
// finally, force a redraw next frame if necessary - only do this when your view
// contents might need to change, otherwise you're wasting resources
if (animating) invalidate()
}
I hope that makes sense - obviously I haven't shown how to actually draw the states of your animation, that depends on exactly what you're doing - but that's the basics of it. It's a lot more work than using view animation, but it's not too bad when you get the idea.
The drawing part is a little more complex, and you'll probably want to get familiar with manipulating the Canvas - e.g. to draw a rotated character, you turn the canvas, draw the character as normal, then undo the canvas rotation so it's the right way up again, and the character is tilted. I don't have time to look for any tutorials about it, but this article covers the matrix operations that scale/rotate/etc the canvas
So yeah, it's a bit involved - and depending on what you want to do, a grid of TextViews might be a better shout
I wrote a Haskell program with Gtk2Hs dealing with Gtk2. But when I tried to build my program with Gtk3, GHC complains about missing functions which doesn't exist anymore :
• Variable not in scope:
widgetGetSize :: GtkGL.GLDrawingArea -> IO (Integer, Integer)
• Variable not in scope:
renderWithDrawable :: t1 -> Render () -> IO ()
Do you know if there are functions in Gtk3 which could replace these functions ?
Is there another way in Gtk3 to get the size of a widget ?
Note : I still can build my program with Gtk2 but I woulk like to anticipate a full migration to Gtk3
GtkGLArea — A widget for custom drawing with OpenGL
API: ( C ) ( Vala )
GtkGLArea is a widget that allows drawing with OpenGL.
GtkGLArea sets up its own GdkGLContext for the window it creates, and
creates a custom GL framebuffer that the widget will do GL rendering
onto. It also ensures that this framebuffer is the default GL
rendering target when rendering.
In order to draw, you have to connect to the “render” signal, or
subclass GtkGLArea and override the GtkGLAreaClass.render() virtual
function.
The GtkGLArea widget ensures that the GdkGLContext is associated with
the widget's drawing area, and it is kept updated when the size and
position of the drawing area changes.
GtkWidget Size
To get the widget size, use the GtkAllocation getters. Notice that GtkWidget has request size methods but the allocated size may differ.
Width: ( C ) ( Vala )
Height: ( C ) ( Vala )
GtkAllocation: ( C ) ( Vala )
I'm experimenting with the sample program at https://github.com/gtk2hs/gtk2hs/blob/master/gtk/demo/hello/World.hs, reproduced below:
-- A simple program to demonstrate Gtk2Hs.
module Main (Main.main) where
import Graphics.UI.Gtk
main :: IO ()
main = do
initGUI
-- Create a new window
window <- windowNew
-- Here we connect the "destroy" event to a signal handler.
-- This event occurs when we call widgetDestroy on the window
-- or if the user closes the window.
on window objectDestroy mainQuit
-- Sets the border width and tile of the window. Note that border width
-- attribute is in 'Container' from which 'Window' is derived.
set window [ containerBorderWidth := 10, windowTitle := "Hello World" ]
-- Creates a new button with the label "Hello World".
button <- buttonNew
set button [ buttonLabel := "Hello World" ]
-- When the button receives the "clicked" signal, it will call the
-- function given as the second argument.
on button buttonActivated (putStrLn "Hello World")
-- Gtk+ allows several callbacks for the same event.
-- This one will cause the window to be destroyed by calling
-- widgetDestroy. The callbacks are called in the sequence they were added.
on button buttonActivated $ do
putStrLn "A \"clicked\"-handler to say \"destroy\""
widgetDestroy window
-- Insert the hello-world button into the window.
set window [ containerChild := button ]
-- The final step is to display this newly created widget. Note that this
-- also allocates the right amount of space to the windows and the button.
widgetShowAll window
-- All Gtk+ applications must have a main loop. Control ends here
-- and waits for an event to occur (like a key press or mouse event).
-- This function returns if the program should finish.
mainGUI
If I build and run this on Mac OS X, Cmd-Q or the Quit command from the app's menu does not close the application. How do I trap this event and cause it to close the app?
Update
I've added a gtk3-mac-integration dependency to my project, an import Graphics.UI.Gtk.OSX to my source file and the following immediately after calling initGUI:
app <- applicationNew
on app willTerminate (return ())
I'm definitely missing something as this doesn't seem to do anything (see https://github.com/rcook/gtkapp/commit/8531509d0648ddb657633a33773c09bc5a576014).
Update no. 2
Thanks to #Jack Henahan and OSXDemo.hs, I now have a working solution:
-- A simple program to demonstrate Gtk2Hs.
module Main (Main.main) where
import Control.Exception
import Control.Monad
import Graphics.UI.Gtk
import Graphics.UI.Gtk.OSX
showDialog :: Window -> String -> String -> IO ()
showDialog window title message = bracket
(messageDialogNew (Just window) [] MessageInfo ButtonsOk message)
widgetDestroy
(\d -> do
set d [ windowTitle := title ]
void $ dialogRun d)
main :: IO ()
main = do
void initGUI
-- Create a new window
window <- windowNew
-- Here we connect the "destroy" event to a signal handler.
-- This event occurs when we call widgetDestroy on the window
-- or if the user closes the window.
void $ on window objectDestroy mainQuit
-- Sets the border width and tile of the window. Note that border width
-- attribute is in 'Container' from which 'Window' is derived.
set window [ containerBorderWidth := 10, windowTitle := "Hello World" ]
-- Creates a new button with the label "Hello World".
button <- buttonNew
set button [ buttonLabel := "Hello World" ]
-- When the button receives the "clicked" signal, it will call the
-- function given as the second argument.
void $ on button buttonActivated (putStrLn "Hello World")
void $ on button buttonActivated $ showDialog window "THE-TITLE" "THE-MESSAGE"
-- Gtk+ allows several callbacks for the same event.
-- This one will cause the window to be destroyed by calling
-- widgetDestroy. The callbacks are called in the sequence they were added.
void $ on button buttonActivated $ do
putStrLn "A \"clicked\"-handler to say \"destroy\""
widgetDestroy window
-- Insert the hello-world button into the window.
set window [ containerChild := button ]
-- The final step is to display this newly created widget. Note that this
-- also allocates the right amount of space to the windows and the button.
widgetShowAll window
app <- applicationNew
-- blockTermination: return True to prevent quit, False to allow
on app blockTermination $ do
putStrLn "blockTermination"
return False
-- willTerminate: handle clean-up etc.
on app willTerminate $ do
putStrLn "willTerminate"
menuBar <- menuBarNew
applicationSetMenuBar app menuBar
applicationReady app
-- All Gtk+ applications must have a main loop. Control ends here
-- and waits for an event to occur (like a key press or mouse event).
-- This function returns if the program should finish.
mainGUI
You need to send an NSApplicationWillTerminate signal.
willTerminate :: ApplicationClass self => Signal self (IO ())
willTerminate = Signal (connect_NONE__NONE "NSApplicationWillTerminate")
is how it's handled in gtk-mac-integration.
I know users can move a window around and make it partially outside of the resolution boundary under X window system. Is it possible to change the size to achieve the same result either programmatically or manually?
Here is my experimental code, but it doesn't work.
Window w;
int revert_to;
XGetInputFocus(m_display, &w, &revert_to);
if (w == None) {
printf("can't get focused window");
}
else {
Window top = get_top_window(m_display, w);
XWindowAttributes xwa;
XGetWindowAttributes(m_display, top, &xwa);
XClassHint xch;
XGetClassHint(m_display, top, &xch);
printf("focused window name: %s pos: %d, %d size: %d, %d", xch.res_class, xwa.x, xwa.y, xwa.width, xwa.height);
XResizeWindow(m_display, top, 900, 1900);
}
get_top_window is some codes from internet
Window get_top_window(Display* d, Window start) {
Window w = start;
Window parent = start;
Window root = None;
Window *children;
unsigned int nchildren;
Status s;
printf("getting top window ... \n");
while (parent != root) {
w = parent;
s = XQueryTree(d, w, &root, &parent, &children, &nchildren); // see man
if (s)
XFree(children);
if(xerror) {
printf("fail\n");
exit(1);
}
printf(" get parent (window: %d)\n", (int)w);
}
printf("success (window: %d)\n", (int)w);
return w;
}
Take terminal as an example, this code could change the inner window but the outline window with titlebar is not affected. is this because the outline window is generated by window manager? And how could I resize it as one unit?
Apart from that, I also can't resize the window out of the resolution boundary. Any solution?
Edit: I use compiz window manager and there is no corresponding setting in Compiz configuration settings manager.
Edit: With the settings in this link, I'm able to resize a window out of the screen resolution by using mouse middle button click and drag trick. But programmatical method is still not working.
In Go, it can be specified which direction a channel can send. I am trying to create an example about it, look at the following code:
package main
import (
"fmt"
"time"
)
func main() {
ic_send_only := make(<-chan int) //a channel that can only send data - arrow going out is sending
ic_recv_only := make(chan<- int) //a channel that can only receive a data - arrow going in is receiving
go func() {
ic_recv_only <- 4555
}()
go func() {
ic_send_only <- ic_recv_only
}()
fmt.Println(ic_recv_only)
time.Sleep(10000)
}
I get the compiler error
# command-line-arguments
.\send_receive.go:19: invalid operation: ic_send_only <- ic_recv_only (send to receive-only type <-chan int)
[Finished in 0.2s with exit code 2]
How can I use channel direction in the right way?
Or does anyone have a better sample than me?
Three issues:
You have the send and receive operations reversed (which is the error you're seeing)
Creating recv-only or send-only channels make no sense, as you cannot use them
The notation you're using is trying to send the channel itself, not the result. You need to receive and send, which requires two arrows.
ic_recv_only <- <-ic_send_only
You may be confused because you have the terminology reversed. <-ch is a "receive operation", and ch <- is a send operation. Note that in your example, everything would be deadlocked because you can't complete the corresponding sends and receives to pass something through either channel.
Here is a complete example:
// This receives an int from a channel. The channel is receive-only
func consumer(ch <-chan int) int {
return <-ch
}
// This sends an int over a channel. The channel is send-only
func producer(i int, ch chan<- int) {
ch <- i
}
func main() {
ch := make(chan int)
go producer(42, ch)
result := consumer(ch)
fmt.Println("received", result)
}
The key point that JimB has made, to summarise, is that
You create channels using make
Every channel has two ends.
You communicate via the ends of channels via <-. The ends are important.
There is a sending end and a receiving end; channels are unidirectional.
Note also that each end can be safely accessed concurrently by more than one goroutine.
Also note that JimB's example producer(i int, ch chan<- int) and consumer(ch <-chan int) functions have parameters that specify which end they use via <-chan and chan<-, instead of just chan. Although this is optional, it is good practice because the compiler will help you fix silly mistakes if you do this.