Page 1 of 1
Rerouting Events to other Gadgets ?
Posted: Mon Sep 10, 2012 7:45 pm
by grabiller
Hi,
Is it possible to reroute an Event from one Gadget to another one ?
For instance let says I have a CanvasGadget and a StringGadget and I want to resend the '#PB_EventType_LeftButtonDown' recieved by the CanvasGadget to the StringGadget when I recieve it.
Is it possible directly in PureBasic ?
On Windows I workaround the problem by subclassing the control, but on linux, I'm not sure what to do.
Any idea ?
Cheers,
Guy.
Re: Rerouting Events to other Gadgets ?
Posted: Mon Sep 10, 2012 8:07 pm
by grabiller
Never mind,
Got the solution:
PB_Gadget_SendGadgetCommand.l(Window.l, EventType.l)
(Internal PB command imported through Import "")
Cheers,
Guy.
Re: Rerouting Events to other Gadgets ?
Posted: Mon Sep 10, 2012 8:20 pm
by grabiller
Hmm, in fact, it's for Windows only, it does not work for Linux..
So my question is still valid.
If someone has an idea ?
Cheers,
Guy.
Re: Rerouting Events to other Gadgets ?
Posted: Mon Sep 10, 2012 9:14 pm
by idle
There are numerous ways to do it but the easiest is to add a signal callback to a gadget
on 32 bit linux you can use
g_signal_connect(gadgetID,Signal$,*function,*userdata)
for 64 bit you need to import it
ImportC "-gtk"
gsignal_connect(instance,signal.p-ascii,*fn,*vdata,destroy=0,flags=0) As "g_signal_connect_data"
EndImport
for details of the signals see
http://developer.gnome.org/gtk/2.24/GtkWidget.html
Here's an example of a workaround fix for the calender gadget so it behaves like it does on windows
Code: Select all
ImportC "-gtk"
gsignal_connect(instance,signal.p-ascii,*fn,*vdata,destroy=0,flags=0) As "g_signal_connect_data"
g_object_set_property(*widget,prop.p-ascii,*val.GValue); ;PB import not defined right for unicode
g_date_new() ;pb import not defined right
g_date_valid(*date.GDate) ;pb import not defined right
EndImport
Macro G_TYPE_MAKE_FUNDAMENTAL(x)
((x) << 2)
EndMacro
#G_TYPE_BOOLEAN = G_TYPE_MAKE_FUNDAMENTAL(5)
Prototype ProtoDateCB(date.s)
Global iCurrentDate.s,idateinvalid.i,ikey
ProcedureC iDateGadgetClick(*editable.GtkEditable,*event.GdkEventButton,*usrdata)
Protected startpos,*entry.GtkEntry,currentdate.s
;get the current date abd set the selection
*entry = *editable
iCurrentdate = PeekS(*entry\text,*entry\text_length,#PB_UTF8)
startpos = gtk_editable_get_position_(*editable)
If (startpos <> 2 And startpos <> 5)
gtk_editable_select_region_(*editable,startpos,startpos+1);
EndIf
EndProcedure
ProcedureC iDateGadgetKeyPress(*editable.GtkEditable,*event.GdkEventKey,*usrdata)
Protected key,startpos,*entry.GtkEntry
Protected *date
;need to test if the key entry is going to result in a valid date
;so check the current entry text and replace the charicter with the new one
key = *event\keyval & $FF
If key >= '0' And key <= '9'
ikey=1
*date = g_date_new()
*entry = *editable
startpos = gtk_editable_get_position_(*editable)
tdate.s = PeekS(*entry\text,*entry\text_length,#PB_UTF8 )
key = *event\keyval & $FF
tdate = Left(tdate,startpos-1) + Chr(key) + Right(tdate,10-startpos)
g_date_set_parse_(*date,tdate)
If g_date_valid(*date)
iCurrentDate = tdate
Else
idateinvalid =1
EndIf
g_date_free_(*date)
EndIf
EndProcedure
ProcedureC iDateGadgetKeyRel(*editable.GtkEditable,*event.GdkEventKey,*usrdata)
Protected key,startpos
;handle arrow keys to move selection
startpos = gtk_editable_get_position_(*editable)
key = *event\keyval & $FF
If startpos > 0
If key = 81
If (startpos <> 3 And startpos <> 6)
startpos -1
Else
startpos-2
EndIf
gtk_editable_select_region_(*editable,startpos,startpos+1);
ElseIf key = 83
If (startpos <> 1 And startpos <> 4)
startpos +1
Else
startpos +2
EndIf
gtk_editable_select_region_(*editable,startpos,startpos+1);
EndIf
EndIf
EndProcedure
ProcedureC iDateChanged(*entry.GtkEntry,*usrdata)
Protected sdate.s, cb.ProtoDateCB
Protected *date
Static eat
cb = *usrdata
If Not idateinvalid
If Not ikey
sdate = Trim(PeekS(*entry\text,*entry\text_length,#PB_UTF8 ))
cb(sdate)
Else
ikey=0
EndIf
Else
;if the date is invalid reset it to the last entry
gtk_entry_set_text_(*entry,iCurrentDate)
idateinvalid = 0
EndIf
EndProcedure
;user functions
Procedure DateGadgetEx(gadget,x,y,width,height,format.s,*cbDateChanged)
Protected *entry,gad
Protected gval.GValue
If gadget = #PB_Any
gad = DateGadget(gadget, x, y, width, height,format)
Else
DateGadget(gadget, x, y, width, height,format)
gad = gadget
EndIf
If *cbDateChanged
*entry = GadgetID(gad);gtk_widget_get_ancestor_(GadgetID(gad), gtk_entry_get_type_());
If *entry
g_value_init_(@gval,#G_TYPE_BOOLEAN)
g_value_set_boolean_(@gval, #True)
g_object_set_property(*entry,"editable",@gval);
gtk_entry_set_max_length_(*entry,10)
gsignal_connect(*entry,"button-release-event",@iDateGadgetClick(),0)
gsignal_connect(*entry,"key-release-event",@iDateGadgetKeyRel(),0)
gsignal_connect(*entry,"key-press-event",@iDateGadgetKeyPress(),0)
gsignal_connect(*entry,"changed",@iDateChanged(),*cbDateChanged)
ProcedureReturn gad
EndIf
EndIf
ProcedureReturn gad
EndProcedure
Procedure DateChanged(sdate.s)
Debug sdate
EndProcedure
If OpenWindow(0, 0, 0, 300, 300, "DateGadgetTest", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
DateGadgetEx(1, 8, 8, 120, 28, "%dd.%mm.%yyyy",@DateChanged())
Repeat
Select WaitWindowEvent()
Case #PB_Event_Gadget
Debug "In Linux no event at all"
Case #PB_Event_CloseWindow
Break
EndSelect
ForEver
EndIf
Re: Rerouting Events to other Gadgets ?
Posted: Mon Sep 10, 2012 9:31 pm
by grabiller
That's exactly what I was looking for.
A big thanks to you.
Cheers,
Guy.
Re: Rerouting Events to other Gadgets ?
Posted: Tue Sep 11, 2012 12:37 am
by grabiller
In fact I would need an additional information:
Once I'm in the iDateGadgetClick callback for instance, what should I do to 'pass-through' or 're-send' the same event I just recieve to another Widget ?
Cheers,
Guy.
Re: Rerouting Events to other Gadgets ?
Posted: Tue Sep 11, 2012 2:55 am
by idle
you can use
Code: Select all
gtk_signal_emit_by_name_(GadgetID,"signal",0);
and catch the event in the main loop
Re: Rerouting Events to other Gadgets ?
Posted: Tue Sep 11, 2012 4:48 am
by grabiller
idle wrote:you can use
Code: Select all
gtk_signal_emit_by_name_(GadgetID,"signal",0);
and catch the event in the main loop
Ah, thanks a lot, it seems to be the solution yes, but strangely when I use it to send to the "other" GadgetID I get an "Invalid Memory Access" (yet the pointer is not null) while when I send it to itself it works ( I get multiple events ).
Yet the "other" GadgetID is used with other gtk api calls without triggering the error. It works.
I'm puzzled.. I'll investigate further..
Cheers,
Guy.
Re: Rerouting Events to other Gadgets ?
Posted: Tue Sep 11, 2012 12:18 pm
by grabiller
I've found the solution, I have to make room for the returned values:
gtk_signal_emit_by_name( GadgetID, "button-press-event", @event, @retval )
It does not crash anymore.
However the signal is not resent in the PB event main loop. Are you sure it should appear in the event main loop ?
Cheers,
Guy.
Re: Rerouting Events to other Gadgets ?
Posted: Tue Sep 11, 2012 8:33 pm
by idle
some but not all events will be caught in the main loop.
but I suppose you could connect a callback to handle the emitted signal.
Re: Rerouting Events to other Gadgets ?
Posted: Tue Sep 11, 2012 9:58 pm
by grabiller
That's what I'm doing but then I need to forward the signal to another widget wich does not recieve the user inputs.
Connecting callbacks to this other widget would be useless as it wont recieve events.
Anyway, I'm still investigating but I'm also reconsidering my linux approach.
Until now I was trying to 'port' my windows code wich works perfectly well (very fast, very easy to forward messages, to alter widgets programmaticaly and have immediate update of the layout before it gets painted, wich does not work on linux afaik).
But perhaps I should considere a different way more suitable to linux/gtk. The challenge beeing to achieve the exact same look and behavior of the widgets accross plateforms (and I did not touched Mac OS X yet.. ). This is the foundation of a heavy project and before I go any further I need to do this part absolutely right.
Someone on IRC suggested me to use only GTK on all tree platforms but I'm not convainced. From my experiments, native win32 UI is much faster (but perhaps someone will prove me wrong) and UI performance is also a big concern to me. Cocoa should be faster than gtk too on Mac ( but I did not use it yet so I can't really be sure). Plus, that would defeat the purpose of taking advantage of PureBasic and it's cross-plateform loop/events system (even though there is a need to use natives api calls here and there but this is far different from integrating a all new toolkit on all tree plateforms into PB).
This is not an easy problem, but I want to find the best approach. Perhaps I should forget all about native api calls and only use custom widgets entierly done in PB with the CanvasGadget. That's what I'll experiment next, I'm not sure about the performances of this approach yet but perhaps this is the solution.
Cheers,
Guy.
Re: Rerouting Events to other Gadgets ?
Posted: Wed Sep 12, 2012 3:54 pm
by BorisTheOld
To avoid the complication of generating events, why not try doing a simple procedure call. We've been using this technique for many years with Visual Basic, Power Basic, and now PB.
If our program needs to create a non-standard or user event in order to process some gadget code, we just call the appropriate procedure and don't bother creating an actual event. This technique allows pseudo-events to be directed at any gadget code we choose. And if timing is an issue then we schedule the call after a known real event, or use a timer set to a short delay.
Another technique is to use standard events in a non-standard way. For example, set up an off-screen gadget that can be used to trap got-focus events, then code its event routine to perform the various functions you need. These events can be initiated from within code by setting focus to the off-screen gadget. You can use this gadget's data word to hold a user message number.
These techniques have the advantage of being cross-platform, because they don't require API code.