Capturing clicks in label_widget in expander (lablgtk) - gtk

In lablgtk, I have an Expander widget to which I added a button as part of its label, as in this picture:
However, I'm unable to capture clicks to this button, since all of them seem to be captured by the Expander object itself.
I even tried adding an event box between the expander and the button (similarly to what is recommended for clickable GLabels), but that did not help.
Is there a way to ensure the button receives the signal?
Here's a self-contained example to illustrate this: clicking on the button only prints expander activated!, but never button clicked!.
let main () =
(* create expander, a label_widget, and a button *)
let expander = GBin.expander () in
let expander_label = GMisc.label ~text:"expander" () in
let expander_label_widget = GPack.hbox () in
let button = GButton.button ~stock:`OK () in
(* add button to label_widget, and label_widget to expander *)
expander_label_widget#add expander_label#coerce;
expander_label_widget#add button#coerce;
expander#set_label_widget expander_label_widget#coerce;
(* add events for both the button and the expander *)
ignore (button#connect#clicked
~callback:(fun () ->
Format.printf "button clicked!#."));
ignore (expander#connect#activate
~callback:(fun () ->
Format.printf "expander activated!#."));
(* create window and add expander *)
let window = GWindow.window () in
window#add expander#coerce;
ignore (window#connect#destroy
~callback:(fun () -> GMain.Main.quit ()));
(* show result *)
window#show ();
GMain.Main.main ()
let () =
ignore (GtkMain.Main.init ());
main ()

This seems to be a bug in GTK+.
There's a workaround described here but it's in C.
You have to add the following OCaml code to your main function. It worked for me.
GMain.Idle.add (fun () ->
let dummy = GButton.button ~stock:`OK () in
expander#set_label_widget dummy#coerce ;
expander#set_label_widget expander_label_widget#coerce ;
false) ;

Related

Complex key bindings in Gtk

Some text editors like sublime or atom support complex key bindins, when you press and release two or more buttons while holding Ctrl or any other modifier key depressed to trigger some action.
There seems to be no direct support of such a concept in Gtk. Of course, one can do something like this:
static second_event_happened = FALSE;
ctrl_k_cb () {
g_timeout_add (500, ctrl_k_timeout, NULL) // queue watching function
// adjust accels so that until timeout ctrl+t calls ctrl_k_t_cb
}
ctrl_k_timeout () {
if (second_event_happened)
second_event_happened = FALSE;
else
ctrl_k_function ();
// reset accels to their normal state, i.e. ctrl+t calls ctrl_t_cb
}
ctrl_t_cb () {
...
}
ctrl_k_t_cb () {
second_event_happened = TRUE;
...
}
However, this approach is error-prone.
Is there a more simple or GTK-ish solution?

How to fix two clicks in dialog

I've created a dialog to ask the user if he really want to proceed creating another file (text buffer). However, there is something with my approach that requires me to click twice at the button yes or at the button no.
What am I doing wrong?
The code for the specific function is:
def createnew ()
var Hello=new MessageDialog (null, Gtk.DialogFlags.MODAL,
Gtk.MessageType.INFO, Gtk.ButtonsType.YES_NO, "Hello world!")
Hello.format_secondary_text ("This will delete the contets. Are you sure?")
Hello.run ()
case Hello.run()
when ResponseType.YES
_view.buffer.set_text("")
Hello.destroy ()
when ResponseType.NO
Hello.destroy ()
The function is working fine otherwise.
You are calling Hello.run () twice. The fist time, you discard the result and the second time you use it for the case block.

How to pack a button in a HeaderBar using Genie?

Background
My aim is to improve a little text editor as an exercise. It is running fine after the HeaderBar was added, however I can't find a way to pack buttons in it.
Code
uses
Granite.Widgets
Gtk
init
Gtk.init (ref args)
var app = new Application ()
app.show_all ()
Gtk.main ()
// This class holds all the elements from the GUI
class Application : Gtk.Window
_view:Gtk.TextView
construct ()
// Prepare Gtk.Window:
this.window_position = Gtk.WindowPosition.CENTER
this.destroy.connect (Gtk.main_quit)
this.set_default_size (400, 400)
// Headerbar definition
headerbar:Gtk.HeaderBar = new Gtk.HeaderBar()
headerbar.show_close_button = true
headerbar.set_title("My text editor")
// Headerbar buttons
var open_button = new ToolButton.from_stock(Stock.Open)
// Add everything to the toolbar
open_button.pack_start ()
show_all ()
this.set_titlebar(headerbar)
// Box:
box:Gtk.Box = new Gtk.Box (Gtk.Orientation.VERTICAL, 1)
this.add (box)
// A ScrolledWindow:
scrolled:Gtk.ScrolledWindow = new Gtk.ScrolledWindow (null, null)
box.pack_start (scrolled, true, true, 0)
// The TextView:
_view = new Gtk.TextView ()
_view.set_wrap_mode (Gtk.WrapMode.WORD)
_view.buffer.text = "Lorem Ipsum"
scrolled.add (_view)
// A Button:
button:Gtk.Button = new Gtk.Button.with_label ("Print content to
stdout")
box.pack_start (button, false, true, 0)
button.clicked.connect (clicked)
// This is a simple stub function to take care of the click
def clicked ()
stdout.puts (_view.buffer.text)
stdout.putc ('\n')
Error
When pack_start (see below) is used, I get the error:
text_editor-exercise_7_1.gs:136.3-136.39: error: Access to instance member `Gtk.HeaderBar.pack_start' denied
Similar errors occur when I use HeaderBar.pack_start or button_name.pack_start.
Question
Am I wrong to believe that pack_start should be used with HeaderBars?
A second smaller problem is regarding the use of Stock icons. For some reason I can't access Stock.Open.
Finally, is there any other source of information on HeaderBar? Valadoc is sparse in this subject (there are no examples or templates).
You are trying to call pack_start on the button, not on the headerbar:
// Add everything to the toolbar
open_button.pack_start ()
The correct code is:
headerbar.pack_start (open_button)

Detecting a Ctrl+click event in lablgtk

This question explains how to detect a ctrl+click in pygtk.
Does it also work on Lablgtk? Or is there a simpler way to do it?
In lablgtk, there is a more direct solution, although it is not immediately obvious.
From a mouse click event ev (of type GdkEvent.Button.t), you can detect events such as ctrl+click/shift+click with GdkEvent.Button.state and Gdk.Convert.modifier), as in the following example:
let state = GdkEvent.Button.state ev in
let modifiers = Gdk.Convert.modifier state in
let button = GdkEvent.Button.button ev in
if button = 1 && List.mem `CONTROL modifiers then
(* Ctrl+left click *) ...
else if button = 3 && List.mem `SHIFT` modifiers then
(* Shift+right click *) ...
The type of the modifier list is Gdk.Tags.modifier.

Click not firing first time after rebind with live() method

I understand that this is a probably a noob-ish question, but I've had no luck with the other threads I've found on the same topic.
I've devised a workaround to hack a views exposed filter to hide and show products with a stock count of "0". The exposed filter for the stock count (input#edit-stock) is hidden with CSS and inside a custom block is a link to manipulate the form and trigger the query (with ajax). This is working great, but with one exception - after resetting the form with the views-provided "reset" button, toggle() will not rebind properly to the link, and click won't fire the first time. Works fine on the 2nd click. I'm sure that the solution is very simple, but I'm at a loss..
How to rebind toggle() effectively?
Sorry, I'm unable to provide a live example. Many thanks for any input.
CUSTOM BLOCK:
<a id="toggle" href="#">exclude</a>
JQUERY:
$(document).ready(function () {
var include = function () {
$('input#edit-stock').attr('value', 0).submit();
$('a#toggle').html('include');
};
var exclude = function () {
$('input#edit-stock').attr('value', '').submit();
$('a#toggle').html('exclude');
};
$('a#toggle').toggle(include, exclude);
$('input#edit-reset').live('click', function (event) {
$('a#toggle').unbind('toggle').toggle(include, exclude).html('exclude');
});
});
if i get the problem right you need to reset the toggle. Why instead of unbind toggle and rebinding it you just don't simulate a click if the link is == to include?
$(document).ready(function () {
var include = function () {
$('input#edit-stock').attr('value', 0).submit();
$('a#toggle').html('include');
};
var exclude = function () {
$('input#edit-stock').attr('value', '').submit();
$('a#toggle').html('exclude');
};
$('a#toggle').toggle(include, exclude);
$('input#edit-reset').live('click', function (event) {
//if the link is include, click it so that it resets to exclude, else do nothing
if ($('a#toggle').html() == 'include'){
$('a#toggle').click();
}
});
});
fiddle here: http://jsfiddle.net/PSLBb/
(Hope this is what you were looking for)