#include "ink-spinscale.h" #include #include #include #include #include #include // Constructor for Gtk::Range is protected... must derive a new class. InkRange::InkRange(Glib::RefPtr adjustment, Gtk::SpinButton* spinbutton) : Glib::ObjectBase("InkRange") , Gtk::Range() , _spinbutton(spinbutton) , _dragging(false) , _drag_start(0) , _drag_offset(0) { set_name("InkRange"); set_adjustment(adjustment); // std::cout << "GType name: " << G_OBJECT_TYPE_NAME(gobj()) << std::endl; } void InkRange::set_label(Glib::ustring label) { _label = label; } bool InkRange::on_draw(const::Cairo::RefPtr<::Cairo::Context>& cr) { // std::cout << "\nInkRange::on_draw" << std::endl; // Get our own style info... // auto style = get_style_context(); // auto state = style->get_state(); // std::cout << "color: " << style->get_color( state ).to_string() << std::endl; // std::cout << "background: " << style->get_background_color( state ).to_string() << std::endl; // std::cout << "border: " << style->get_border_color( state ).to_string() << std::endl; // Get SpinButton style info... auto style_spin = _spinbutton->get_style_context(); auto state_spin = style_spin->get_state(); Gdk::RGBA text_color = style_spin->get_color( state_spin ); // Create Pango layout. auto layout_label = create_pango_layout(_label); layout_label->set_ellipsize( Pango::ELLIPSIZE_END ); layout_label->set_width(PANGO_SCALE * get_width()); // Get y location of SpinButton text (to match vertical position of SpinButton text). int x, y; _spinbutton->get_layout_offsets(x, y); // Render text in normal text color. cr->save(); Gdk::Cairo::set_source_rgba(cr, text_color); cr->set_source_rgba(0, 0, 0, 1); cr->move_to(5, y ); layout_label->show_in_cairo_context(cr); cr->restore(); // Fill widget proportional to value. double fraction = get_fraction(); // Render bar (over normal text to reduce blurriness). Gdk::RGBA fill_color("rgba(74,144,217,1.0)"); Gdk::Cairo::set_source_rgba(cr, fill_color); cr->rectangle(0, 0, get_width() * fraction, get_height()); cr->fill_preserve(); // Save rectangle for clipping text. // Render text, clipped, in white over bar (TODO: use same color as SpinButton progress bar). cr->save(); cr->clip(); cr->set_source_rgba(1, 1, 1, 1); cr->move_to(5, y); layout_label->show_in_cairo_context(cr); cr->restore(); return false; } bool InkRange::on_button_press_event(GdkEventButton* button_event) { _dragging = true; if (! (button_event->state & GDK_MOD1_MASK) ) { set_adjustment_value(button_event->x); } // Dragging must be initialized after any adjustment due to button press. _dragging = true; _drag_start = button_event->x; _drag_offset = get_width() * get_fraction(); return true; } bool InkRange::on_button_release_event(GdkEventButton* button_event) { _dragging = false; return true; } bool InkRange::on_motion_notify_event(GdkEventMotion* motion_event) { double x = motion_event->x; double y = motion_event->y; if (_dragging) { if (! (motion_event->state & GDK_MOD1_MASK) ) { // Absolute change set_adjustment_value(x); } else { // Relative change double xx = (_drag_offset + (x - _drag_start) * 0.1); set_adjustment_value(xx); } return true; } if (! (motion_event->state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK))) { auto display = get_display(); auto cursor = Gdk::Cursor::create(display, Gdk::SB_DOWN_ARROW); // Get Gdk::window (not Gtk::window).. set cursor for entire window. // Would need to unset with leave event. // get_window()->set_cursor( cursor ); // Can't see how to do this the C++ way since GdkEventMotion // is a structure with a C window member. There is a gdkmm // wrapping function for Gdk::EventMotion but only in unstable. gdk_window_set_cursor( motion_event->window, cursor->gobj() ); } return false; } double InkRange::get_fraction() { Glib::RefPtr adjustment = get_adjustment(); double upper = adjustment->get_upper(); double lower = adjustment->get_lower(); double value = adjustment->get_value(); double fraction = (value - lower)/(upper - lower); return fraction; } void InkRange::set_adjustment_value(double x) { Glib::RefPtr adjustment = get_adjustment(); double upper = adjustment->get_upper(); double lower = adjustment->get_lower(); double fraction = x / (double)get_width(); double value = fraction * (upper - lower) + lower; adjustment->set_value( value ); } /*******************************************************************/ InkSpinScale::InkSpinScale(double value, double lower, double upper, double step_increment, double page_increment, double page_size) { set_name("InkSpinScale"); g_assert (upper - lower > 0); _adjustment = Gtk::Adjustment::create(value, lower, upper, step_increment, page_increment, page_size); _spinbutton = Gtk::manage(new Gtk::SpinButton(_adjustment)); _spinbutton->set_numeric(); _spinbutton->signal_key_release_event().connect(sigc::mem_fun(*this,&InkSpinScale::on_key_release_event),false); _range = Gtk::manage(new InkRange(_adjustment, _spinbutton)); pack_end( *_spinbutton, Gtk::PACK_SHRINK ); pack_end( *_range, Gtk::PACK_EXPAND_WIDGET ); } InkSpinScale::InkSpinScale(Glib::RefPtr adjustment) : _adjustment(adjustment) { set_name("InkSpinScale"); g_assert (_adjustment->get_upper() - _adjustment->get_lower() > 0); _spinbutton = Gtk::manage(new Gtk::SpinButton(_adjustment)); _spinbutton->set_numeric(); _range = Gtk::manage(new InkRange(_adjustment, _spinbutton)); pack_end( *_spinbutton, Gtk::PACK_SHRINK ); pack_end( *_range, Gtk::PACK_EXPAND_WIDGET ); } void InkSpinScale::set_label(Glib::ustring label) { _range->set_label(label); } void InkSpinScale::set_digits(int digits) { _spinbutton->set_digits(digits); } int InkSpinScale::get_digits() const { return _spinbutton->get_digits(); } void InkSpinScale::set_focus_widget(GtkWidget * focus_widget) { _focus_widget = focus_widget; } // Return focus to canvas. bool InkSpinScale::on_key_release_event(GdkEventKey* key_event) { switch (key_event->keyval) { case GDK_KEY_Escape: case GDK_KEY_Return: case GDK_KEY_KP_Enter: { if (_focus_widget) { gtk_widget_grab_focus( _focus_widget ); } } break; } return false; }