void dragable:: on_mouse_move ( unsigned long state, long x, long y ) { if (drag && (state & base_window::LEFT) && enabled && !hidden) { // the user is trying to drag this object. we should calculate the new // x and y positions for the upper left corner of this object's rectangle long new_x = x - this->x; long new_y = y - this->y; // make sure these points are inside the dragable area. if (new_x < area.left()) new_x = area.left(); if (new_x + static_cast<long>(rect.width()) - 1 > area.right()) new_x = area.right() - rect.width() + 1; if (new_y + static_cast<long>(rect.height()) - 1 > area.bottom()) new_y = area.bottom() - rect.height() + 1; if (new_y < area.top()) new_y = area.top(); // now make the new rectangle for this object rectangle new_rect( new_x, new_y, new_x + rect.width() - 1, new_y + rect.height() - 1 ); // only do anything if this is a new rectangle and it is inside area if (new_rect != rect && area.intersect(new_rect) == new_rect) { parent.invalidate_rectangle(new_rect + rect); rect = new_rect; // call the on_drag() event handler on_drag(); } } else { drag = false; } }
// widget developer functions: void UIWidget::mouse_axes_func(float x, float y, float dx, float dy) { if (disabled) return; // start by transforming the coordinates for the children local_mouse_x = x; local_mouse_y = y; float tmdx = dx; float tmdy = dy; surface_area->placement.transform_coordinates(&local_mouse_x, &local_mouse_y); surface_area->placement.transform_coordinates(&tmdx, &tmdy); UIWidget *parent = static_cast<UIWidget *>(get_parent()); if (parent && parent->mouse_is_blocked) mouse_is_blocked = true; else mouse_is_blocked = false; //for (int i=(int)children.size()-1; i>=0; i--) //children[i]->mouse_axes_func(local_mouse_x, local_mouse_y, dx, dy); // I'm not sure why these are dx/dy, but it works correctly this way for (auto &child : ElementID::recast_collection<UIWidget>(get_children())) child->mouse_axes_func(local_mouse_x, local_mouse_y, dx, dy); // I'm not sure why these are dx/dy, but it works correctly this way // then proceed with the execution of the function if (surface_area) { bool mouse_over_now = surface_area->collides(x, y); if (parent && parent->mouse_is_blocked) mouse_over_now = false; if (mouse_over_now && !mouse_over) on_mouse_enter(); else if (!mouse_over_now && mouse_over) on_mouse_leave(); mouse_over = mouse_over_now; if (parent && mouse_over) parent->mouse_is_blocked = true; } on_mouse_move(x, y, dx, dy); // TODO I think this needs to be the translated coordinates, and maybe even should be on the on_drag() call below as well if (mouse_down_on_over) { dragging = true; on_drag(x, y, dx, dy); } if (Framework::current_event->mouse.dz != 0 || Framework::current_event->mouse.dw != 0) on_mouse_wheel(); }
/** Event handler to fire (higher level, abstracted) Item signals from Gtk events. */ bool Item::on_event(GdkEvent* event) { boost::shared_ptr<Canvas> canvas = _canvas.lock(); if (!canvas || !event) return false; static double x, y; static double drag_start_x, drag_start_y; static bool double_click = false; static bool dragging = false; double click_x, click_y; click_x = event->button.x; click_y = event->button.y; property_parent().get_value()->w2i(click_x, click_y); switch (event->type) { case GDK_2BUTTON_PRESS: if (dragging) { ungrab(event->button.time); dragging = false; } on_double_click(&event->button); double_click = true; break; case GDK_BUTTON_PRESS: if (!canvas->locked() && event->button.button == 1) { x = click_x; y = click_y; // Set these so we can tell on a button release if a drag actually // happened (if not, it's just a click) drag_start_x = x; drag_start_y = y; grab(GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK|GDK_BUTTON_PRESS_MASK, Gdk::Cursor(Gdk::FLEUR), event->button.time); dragging = true; } break; case GDK_MOTION_NOTIFY: if ((dragging && (event->motion.state & GDK_BUTTON1_MASK))) { double new_x = click_x; double new_y = click_y; if (event->motion.is_hint) { int t_x; int t_y; GdkModifierType state; gdk_window_get_pointer(event->motion.window, &t_x, &t_y, &state); new_x = t_x; new_y = t_y; } on_drag(new_x - x, new_y - y); x = new_x; y = new_y; } break; case GDK_BUTTON_RELEASE: if (dragging) { ungrab(event->button.time); dragging = false; if (click_x != drag_start_x || click_y != drag_start_y) { on_drop(); } else if (!double_click) { on_click(&event->button); } } else if (!double_click) { on_click(&event->button); } double_click = false; break; case GDK_ENTER_NOTIFY: canvas->signal_item_entered.emit(this); raise_to_top(); break; case GDK_LEAVE_NOTIFY: canvas->signal_item_left.emit(this); break; default: break; } // Never stop event propagation so derived classes have full access // to GTK events. return false; }