I made a custom Right-to-Left check button widget using a Gtk::CheckButton
without the label and a Gtk::Label
inside Gtk::EventBox
.
The reason I went this way instead of simply calling set_direction(Gtk::TEXT_DIR_RTL)
is that I want to manually specify the alignment for these widgets.
I've figured out activating/deactivating checkbutton state when the label's clicked but I'm having trouble triggering the hover event from label to checkbutton. The default Gtk::CheckButton
behavior triggers the hover effect on the clickable square button to indicate it's being activated when text is hovered too. How do I achieve that same behavior on my custom right-to-left checkbutton widget?
Below is the minimal reproducible code for testing:
#include <gtkmm.h>
using Gtk::Application;
using Gtk::Button;
using Gtk::CheckButton;
using Gtk::EventBox;
using Gtk::Grid;
using Gtk::Label;
using Gtk::Window;
class MyWindow : public Window {
Button button;
CheckButton checkbutton;
EventBox eventbox;
Grid grid;
Label label;
bool on_label_clicked(GdkEventButton *);
void arrange_content_layout();
public:
MyWindow();
};
bool MyWindow::on_label_clicked(GdkEventButton *event)
{
if (event->button == 1 && event->type == GDK_BUTTON_PRESS) {
checkbutton.set_active(!checkbutton.get_active());
return true;
}
return false;
}
void MyWindow::arrange_content_layout()
{
checkbutton.set_margin_start(6);
button.set_margin_top(24);
grid.child_property_width(button) = 2;
grid.set_margin_top(24);
grid.set_margin_start(24);
grid.set_margin_end(24);
grid.set_margin_bottom(24);
}
MyWindow::MyWindow()
: button("Click to steal focus")
, label ("Our custom RTL label")
{
eventbox.add(label);
eventbox.signal_button_press_event().connect(sigc::mem_fun(
*this, &MyWindow::on_label_clicked));
grid.add(eventbox);
grid.add(checkbutton);
grid.attach(button, 0, 1);
add(grid);
arrange_content_layout();
set_default_size(120, 60);
show_all();
}
int main()
{
auto app = Application::create("domain.reverse.sample.rtl-checkbutton");
MyWindow window;
return app->run(window);
}
One way is to use set_state_flags()
and trick the visual output of your Right-to-Left checkbutton when the label is being hovered.
First, you need to enable these two masks for eventbox
to capture enter and leave event:
eventbox.add_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK);
And connect eventbox
signals
class MyWindow : public Window {
...
bool on_label_entered(GdkEventCrossing *);
bool on_label_exited(GdkEventCrossing *);
...
}
MyWindow::MyWindow()
...
{
...
eventbox.signal_enter_notify_event().connect(sigc::mem_fun(
*this, &MyWindow::on_label_entered));
eventbox.signal_leave_notify_event().connect(sigc::mem_fun(
*this, &MyWindow::on_label_exited));
...
And finally, use Gtk::STATE_FLAG_PRELIGHT
to do the UI trick
// Enter event
bool MyWindow::on_label_entered(GdkEventCrossing *event)
{
if (event->mode != GDK_CROSSING_NORMAL) return false;
checkbutton.set_state_flags(checkbutton.get_state_flags() | Gtk::STATE_FLAG_PRELIGHT);
return true;
}
// Leave event
bool MyWindow::on_label_exited(GdkEventCrossing *event)
{
if (event->mode != GDK_CROSSING_NORMAL) return false;
checkbutton.unset_state_flags(Gtk::STATE_FLAG_PRELIGHT);
return true;
}