mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-30 04:20:23 +00:00
Win32: Add support to convert mouse messages (WM_) to ui::Messages (using she::Events)
On Windows, instead of polling Allegro mouse position/buttons we can use the mouse messages (WM_*) directly to generate she::Events. Those events are received by the ui::Manager and converted to ui::Messages. Maybe this is a possible fix for issue #133 (Wacom tablets don't work properly). Changes: - Don't use jmouse_z() directly (new ui::MouseMessage::wheelDelta() member) - Add ui::_internal_set_mouse_position() to change the jmouse_x/y(0) from the new mouse position received in she::Events. The same for ui::_internal_set_mouse_buttons(). - Modify the ui::Manager to generate mouse events in any case: using old Allegro 4 polling method, or from she::Events.
This commit is contained in:
parent
2e9751fef1
commit
dd2ce20e25
@ -215,6 +215,7 @@ if(WIN32)
|
||||
shlwapi
|
||||
psapi
|
||||
wininet
|
||||
comctl32
|
||||
dbghelp
|
||||
)
|
||||
|
||||
|
@ -262,7 +262,7 @@ bool StandbyState::onMouseMove(Editor* editor, MouseMessage* msg)
|
||||
|
||||
bool StandbyState::onMouseWheel(Editor* editor, MouseMessage* msg)
|
||||
{
|
||||
int dz = jmouse_z(1) - jmouse_z(0);
|
||||
int dz = -msg->wheelDelta();
|
||||
WHEEL_ACTION wheelAction = WHEEL_NONE;
|
||||
bool scrollBigSteps = false;
|
||||
|
||||
|
@ -273,7 +273,7 @@ bool FileList::onProcessMessage(Message* msg)
|
||||
View* view = View::getView(this);
|
||||
if (view) {
|
||||
gfx::Point scroll = view->getViewScroll();
|
||||
scroll.y += (jmouse_z(1)-jmouse_z(0)) * 3*(2+getTextHeight()+2);
|
||||
scroll.y += -static_cast<MouseMessage*>(msg)->wheelDelta() * 3*(2+getTextHeight()+2);
|
||||
view->setViewScroll(scroll);
|
||||
}
|
||||
break;
|
||||
|
@ -255,7 +255,7 @@ bool PaletteView::onProcessMessage(Message* msg)
|
||||
View* view = View::getView(this);
|
||||
if (view) {
|
||||
gfx::Point scroll = view->getViewScroll();
|
||||
scroll.y += (jmouse_z(1)-jmouse_z(0)) * 3 * m_boxsize;
|
||||
scroll.y += -static_cast<MouseMessage*>(msg)->wheelDelta() * 3 * m_boxsize;
|
||||
view->setViewScroll(scroll);
|
||||
}
|
||||
break;
|
||||
|
@ -286,7 +286,7 @@ bool Tabs::onProcessMessage(Message* msg)
|
||||
return true;
|
||||
|
||||
case kMouseWheelMessage: {
|
||||
int dx = (jmouse_z(1) - jmouse_z(0)) * getBounds().w/6;
|
||||
int dx = -static_cast<MouseMessage*>(msg)->wheelDelta() * getBounds().w/6;
|
||||
// setScrollX(m_scrollX+dx);
|
||||
|
||||
m_begScrollX = m_scrollX;
|
||||
|
@ -739,7 +739,7 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
|
||||
case kMouseWheelMessage:
|
||||
if (m_document) {
|
||||
int dz = jmouse_z(1) - jmouse_z(0);
|
||||
int dz = -static_cast<MouseMessage*>(msg)->wheelDelta();
|
||||
int dx = 0;
|
||||
int dy = 0;
|
||||
|
||||
|
@ -254,7 +254,7 @@ bool ToolBar::onProcessMessage(Message* msg)
|
||||
MouseMessage* mouseMsg2 = new MouseMessage(
|
||||
kMouseDownMessage,
|
||||
mouseMsg->buttons(),
|
||||
mouseMsg->position());
|
||||
mouseMsg->position(), 0);
|
||||
mouseMsg2->addRecipient(strip);
|
||||
getManager()->enqueueMessage(mouseMsg2);
|
||||
}
|
||||
@ -712,7 +712,7 @@ bool ToolBar::ToolStrip::onProcessMessage(Message* msg)
|
||||
MouseMessage* mouseMsg2 = new MouseMessage(
|
||||
kMouseDownMessage,
|
||||
mouseMsg->buttons(),
|
||||
mouseMsg->position());
|
||||
mouseMsg->position(), 0);
|
||||
mouseMsg2->addRecipient(bar);
|
||||
getManager()->enqueueMessage(mouseMsg2);
|
||||
}
|
||||
|
@ -13,7 +13,8 @@ namespace she {
|
||||
enum Capabilities {
|
||||
kMultipleDisplaysCapability = 1,
|
||||
kCanResizeDisplayCapability = 2,
|
||||
kDisplayScaleCapability = 4
|
||||
kDisplayScaleCapability = 4,
|
||||
kMouseEventsCapability = 8,
|
||||
};
|
||||
|
||||
} // namespace she
|
||||
|
@ -8,6 +8,8 @@
|
||||
#define SHE_EVENT_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "gfx/point.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -18,6 +20,20 @@ namespace she {
|
||||
enum Type {
|
||||
None,
|
||||
DropFiles,
|
||||
MouseEnter,
|
||||
MouseLeave,
|
||||
MouseMove,
|
||||
MouseDown,
|
||||
MouseUp,
|
||||
MouseWheel,
|
||||
MouseDoubleClick,
|
||||
};
|
||||
|
||||
enum MouseButton {
|
||||
NoneButton,
|
||||
LeftButton,
|
||||
RightButton,
|
||||
MiddleButton
|
||||
};
|
||||
|
||||
typedef std::vector<std::string> Files;
|
||||
@ -25,14 +41,23 @@ namespace she {
|
||||
Event() : m_type(None) { }
|
||||
|
||||
int type() const { return m_type; }
|
||||
void setType(Type type) { m_type = type; }
|
||||
|
||||
const Files& files() const { return m_files; }
|
||||
gfx::Point position() const { return m_position; }
|
||||
MouseButton button() const { return m_button; }
|
||||
int delta() const { return m_delta; }
|
||||
|
||||
void setType(Type type) { m_type = type; }
|
||||
void setFiles(const Files& files) { m_files = files; }
|
||||
void setPosition(const gfx::Point& pos) { m_position = pos; }
|
||||
void setButton(MouseButton button) { m_button = button; }
|
||||
void setDelta(int delta) { m_delta = delta; }
|
||||
|
||||
private:
|
||||
Type m_type;
|
||||
Files m_files;
|
||||
gfx::Point m_position;
|
||||
MouseButton m_button;
|
||||
int m_delta;
|
||||
};
|
||||
|
||||
} // namespace she
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "she.h"
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/concurrent_queue.h"
|
||||
#include "base/string.h"
|
||||
|
||||
#include <allegro.h>
|
||||
@ -19,6 +20,9 @@
|
||||
#ifdef WIN32
|
||||
#include <winalleg.h>
|
||||
|
||||
#include <windowsx.h>
|
||||
#include <commctrl.h>
|
||||
|
||||
#if defined STRICT || defined __GNUC__
|
||||
typedef WNDPROC wndproc_t;
|
||||
#else
|
||||
@ -36,6 +40,7 @@
|
||||
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
#define DISPLAY_FLAG_FULL_REFRESH 1
|
||||
#define DISPLAY_FLAG_WINDOW_RESIZE 2
|
||||
@ -153,20 +158,19 @@ public:
|
||||
}
|
||||
|
||||
void getEvent(Event& event) {
|
||||
if (m_events.size() > 0) {
|
||||
event = m_events[0];
|
||||
m_events.erase(m_events.begin());
|
||||
}
|
||||
else
|
||||
if (!m_events.try_pop(event))
|
||||
event.setType(Event::None);
|
||||
}
|
||||
|
||||
void queueEvent(const Event& event) {
|
||||
m_events.push_back(event);
|
||||
m_events.push(event);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Event> m_events;
|
||||
// We need a concurrent queue because events are generated in one
|
||||
// thread (the thread created by Allegro 4 for the HWND), and
|
||||
// consumed in the other thread (the main/program logic thread).
|
||||
base::concurrent_queue<Event> m_events;
|
||||
};
|
||||
|
||||
#if WIN32
|
||||
@ -174,35 +178,137 @@ namespace {
|
||||
|
||||
Display* unique_display = NULL;
|
||||
wndproc_t base_wndproc = NULL;
|
||||
bool display_has_mouse = false;
|
||||
int display_scale;
|
||||
|
||||
static void queue_event(Event& ev)
|
||||
{
|
||||
static_cast<Alleg4EventQueue*>(unique_display->getEventQueue())->queueEvent(ev);
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
switch (msg) {
|
||||
|
||||
case WM_DROPFILES:
|
||||
{
|
||||
HDROP hdrop = (HDROP)(wparam);
|
||||
Event::Files files;
|
||||
case WM_DROPFILES: {
|
||||
HDROP hdrop = (HDROP)(wparam);
|
||||
Event::Files files;
|
||||
|
||||
int count = DragQueryFile(hdrop, 0xFFFFFFFF, NULL, 0);
|
||||
for (int index=0; index<count; ++index) {
|
||||
int length = DragQueryFile(hdrop, index, NULL, 0);
|
||||
if (length > 0) {
|
||||
std::vector<TCHAR> str(length+1);
|
||||
DragQueryFile(hdrop, index, &str[0], str.size());
|
||||
files.push_back(base::to_utf8(&str[0]));
|
||||
}
|
||||
int count = DragQueryFile(hdrop, 0xFFFFFFFF, NULL, 0);
|
||||
for (int index=0; index<count; ++index) {
|
||||
int length = DragQueryFile(hdrop, index, NULL, 0);
|
||||
if (length > 0) {
|
||||
std::vector<TCHAR> str(length+1);
|
||||
DragQueryFile(hdrop, index, &str[0], str.size());
|
||||
files.push_back(base::to_utf8(&str[0]));
|
||||
}
|
||||
|
||||
DragFinish(hdrop);
|
||||
|
||||
Event ev;
|
||||
ev.setType(Event::DropFiles);
|
||||
ev.setFiles(files);
|
||||
static_cast<Alleg4EventQueue*>(unique_display->getEventQueue())
|
||||
->queueEvent(ev);
|
||||
}
|
||||
|
||||
DragFinish(hdrop);
|
||||
|
||||
Event ev;
|
||||
ev.setType(Event::DropFiles);
|
||||
ev.setFiles(files);
|
||||
queue_event(ev);
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_MOUSEMOVE: {
|
||||
Event ev;
|
||||
ev.setPosition(gfx::Point(
|
||||
GET_X_LPARAM(lparam) / display_scale,
|
||||
GET_Y_LPARAM(lparam) / display_scale));
|
||||
|
||||
if (!display_has_mouse) {
|
||||
display_has_mouse = true;
|
||||
|
||||
ev.setType(Event::MouseEnter);
|
||||
queue_event(ev);
|
||||
|
||||
// Track mouse to receive WM_MOUSELEAVE message.
|
||||
TRACKMOUSEEVENT tme;
|
||||
tme.cbSize = sizeof(TRACKMOUSEEVENT);
|
||||
tme.dwFlags = TME_LEAVE;
|
||||
tme.hwndTrack = hwnd;
|
||||
_TrackMouseEvent(&tme);
|
||||
}
|
||||
|
||||
ev.setType(Event::MouseMove);
|
||||
queue_event(ev);
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_MOUSELEAVE: {
|
||||
display_has_mouse = false;
|
||||
|
||||
Event ev;
|
||||
ev.setType(Event::MouseLeave);
|
||||
queue_event(ev);
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_RBUTTONDOWN:
|
||||
case WM_MBUTTONDOWN: {
|
||||
Event ev;
|
||||
ev.setType(Event::MouseDown);
|
||||
ev.setPosition(gfx::Point(
|
||||
GET_X_LPARAM(lparam) / display_scale,
|
||||
GET_Y_LPARAM(lparam) / display_scale));
|
||||
ev.setButton(
|
||||
msg == WM_LBUTTONDOWN ? Event::LeftButton:
|
||||
msg == WM_RBUTTONDOWN ? Event::RightButton:
|
||||
msg == WM_MBUTTONDOWN ? Event::MiddleButton: Event::NoneButton);
|
||||
queue_event(ev);
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_LBUTTONUP:
|
||||
case WM_RBUTTONUP:
|
||||
case WM_MBUTTONUP: {
|
||||
Event ev;
|
||||
ev.setType(Event::MouseUp);
|
||||
ev.setPosition(gfx::Point(
|
||||
GET_X_LPARAM(lparam) / display_scale,
|
||||
GET_Y_LPARAM(lparam) / display_scale));
|
||||
ev.setButton(
|
||||
msg == WM_LBUTTONUP ? Event::LeftButton:
|
||||
msg == WM_RBUTTONUP ? Event::RightButton:
|
||||
msg == WM_MBUTTONUP ? Event::MiddleButton: Event::NoneButton);
|
||||
queue_event(ev);
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_LBUTTONDBLCLK:
|
||||
case WM_MBUTTONDBLCLK:
|
||||
case WM_RBUTTONDBLCLK: {
|
||||
Event ev;
|
||||
ev.setType(Event::MouseDoubleClick);
|
||||
ev.setPosition(gfx::Point(
|
||||
GET_X_LPARAM(lparam) / display_scale,
|
||||
GET_Y_LPARAM(lparam) / display_scale));
|
||||
ev.setButton(
|
||||
msg == WM_LBUTTONDBLCLK ? Event::LeftButton:
|
||||
msg == WM_RBUTTONDBLCLK ? Event::RightButton:
|
||||
msg == WM_MBUTTONDBLCLK ? Event::MiddleButton: Event::NoneButton);
|
||||
queue_event(ev);
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_MOUSEWHEEL: {
|
||||
RECT rc;
|
||||
::GetWindowRect(hwnd, &rc);
|
||||
|
||||
Event ev;
|
||||
ev.setType(Event::MouseWheel);
|
||||
ev.setPosition((gfx::Point(
|
||||
GET_X_LPARAM(lparam),
|
||||
GET_Y_LPARAM(lparam)) - gfx::Point(rc.left, rc.top))
|
||||
/ display_scale);
|
||||
ev.setDelta(((short)HIWORD(wparam)) / WHEEL_DELTA);
|
||||
queue_event(ev);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return ::CallWindowProc(base_wndproc, hwnd, msg, wparam, lparam);
|
||||
@ -306,6 +412,7 @@ public:
|
||||
|
||||
void setScale(int scale) OVERRIDE {
|
||||
ASSERT(scale >= 1);
|
||||
display_scale = scale;
|
||||
|
||||
if (m_scale == scale)
|
||||
return;
|
||||
@ -403,7 +510,12 @@ public:
|
||||
}
|
||||
|
||||
Capabilities capabilities() const {
|
||||
return kCanResizeDisplayCapability;
|
||||
return (Capabilities)
|
||||
(kCanResizeDisplayCapability
|
||||
#ifdef WIN32
|
||||
| kMouseEventsCapability
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
Display* createDisplay(int width, int height, int scale) {
|
||||
|
@ -436,8 +436,7 @@ bool ComboBoxEntry::onProcessMessage(Message* msg)
|
||||
releaseMouse();
|
||||
|
||||
MouseMessage mouseMsg2(kMouseDownMessage,
|
||||
mouseMsg->buttons(),
|
||||
mouseMsg->position());
|
||||
mouseMsg->buttons(), mouseMsg->position(), 0);
|
||||
pick->sendMessage(&mouseMsg2);
|
||||
return true;
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ bool IntEntry::onProcessMessage(Message* msg)
|
||||
|
||||
MouseMessage mouseMsg2(kMouseDownMessage,
|
||||
mouseMsg->buttons(),
|
||||
mouseMsg->position());
|
||||
mouseMsg->position(), 0);
|
||||
m_slider->sendMessage(&mouseMsg2);
|
||||
}
|
||||
}
|
||||
@ -93,7 +93,7 @@ bool IntEntry::onProcessMessage(Message* msg)
|
||||
case kMouseWheelMessage:
|
||||
if (isEnabled()) {
|
||||
int oldValue = getValue();
|
||||
int newValue = oldValue + jmouse_z(0) - jmouse_z(1);
|
||||
int newValue = oldValue + static_cast<MouseMessage*>(msg)->wheelDelta();
|
||||
newValue = MID(m_min, newValue, m_max);
|
||||
if (newValue != oldValue) {
|
||||
setValue(newValue);
|
||||
|
@ -185,7 +185,7 @@ bool ListBox::onProcessMessage(Message* msg)
|
||||
View* view = View::getView(this);
|
||||
if (view) {
|
||||
gfx::Point scroll = view->getViewScroll();
|
||||
scroll.y += (jmouse_z(1) - jmouse_z(0)) * getTextHeight()*3;
|
||||
scroll.y += -static_cast<MouseMessage*>(msg)->wheelDelta() * getTextHeight()*3;
|
||||
view->setViewScroll(scroll);
|
||||
}
|
||||
break;
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "she/display.h"
|
||||
#include "she/event.h"
|
||||
#include "she/event_queue.h"
|
||||
#include "she/system.h"
|
||||
#include "ui/intern.h"
|
||||
#include "ui/ui.h"
|
||||
|
||||
@ -65,6 +66,8 @@ struct Filter
|
||||
typedef std::list<Message*> Messages;
|
||||
typedef std::list<Filter*> Filters;
|
||||
|
||||
static bool mouse_events_from_she;
|
||||
|
||||
static int double_click_level;
|
||||
static MouseButtons double_click_buttons;
|
||||
static int double_click_ticks;
|
||||
@ -114,6 +117,7 @@ Manager::Manager()
|
||||
, m_clipboard(NULL)
|
||||
, m_eventQueue(NULL)
|
||||
, m_lockedWindow(NULL)
|
||||
, m_mouseButtons(kButtonNone)
|
||||
{
|
||||
if (!m_defaultManager) {
|
||||
// Hook the window close message
|
||||
@ -145,8 +149,13 @@ Manager::Manager()
|
||||
setVisible(true);
|
||||
|
||||
// Default manager is the first one (and is always visible).
|
||||
if (!m_defaultManager)
|
||||
if (!m_defaultManager) {
|
||||
m_defaultManager = this;
|
||||
|
||||
mouse_events_from_she =
|
||||
((she::Instance()->capabilities() & she::kMouseEventsCapability)
|
||||
== she::kMouseEventsCapability);
|
||||
}
|
||||
}
|
||||
|
||||
Manager::~Manager()
|
||||
@ -202,10 +211,6 @@ void Manager::run()
|
||||
|
||||
bool Manager::generateMessages()
|
||||
{
|
||||
Widget* widget;
|
||||
Widget* window;
|
||||
int c;
|
||||
|
||||
// Poll keyboard
|
||||
poll_keyboard();
|
||||
|
||||
@ -223,7 +228,7 @@ bool Manager::generateMessages()
|
||||
// New windows to show?
|
||||
if (!new_windows.empty()) {
|
||||
UI_FOREACH_WIDGET(new_windows, it) {
|
||||
window = *it;
|
||||
Widget* window = *it;
|
||||
|
||||
// Relayout
|
||||
window->layout();
|
||||
@ -246,56 +251,46 @@ bool Manager::generateMessages()
|
||||
new_windows.clear();
|
||||
}
|
||||
|
||||
if (!mouse_events_from_she)
|
||||
generateMouseMessages();
|
||||
|
||||
// Generate Close message when the user press close button on the system window.
|
||||
if (want_close_stage == STAGE_WANT_CLOSE) {
|
||||
want_close_stage = STAGE_NORMAL;
|
||||
|
||||
Message* msg = new Message(kCloseAppMessage);
|
||||
msg->broadcastToChildren(this);
|
||||
enqueueMessage(msg);
|
||||
}
|
||||
|
||||
generateKeyMessages();
|
||||
generateMessagesFromSheEvents();
|
||||
|
||||
// Generate messages for timers
|
||||
Timer::pollTimers();
|
||||
|
||||
// Generate redraw events.
|
||||
flushRedraw();
|
||||
|
||||
if (!msg_queue.empty())
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void Manager::generateMouseMessages()
|
||||
{
|
||||
// Update mouse status
|
||||
bool mousemove = jmouse_poll();
|
||||
if (mousemove || !mouse_widget) {
|
||||
// Get the list of widgets to send mouse messages.
|
||||
mouse_widgets_list.clear();
|
||||
broadcastMouseMessage(mouse_widgets_list);
|
||||
|
||||
// Get the widget under the mouse
|
||||
widget = NULL;
|
||||
gfx::Point mousePos(gfx::Point(jmouse_x(0), jmouse_y(0)));
|
||||
|
||||
UI_FOREACH_WIDGET(mouse_widgets_list, it) {
|
||||
widget = (*it)->pick(gfx::Point(jmouse_x(0), jmouse_y(0)));
|
||||
if (widget)
|
||||
break;
|
||||
}
|
||||
|
||||
// Fixup "mouse" flag
|
||||
if (widget != mouse_widget) {
|
||||
if (!widget)
|
||||
freeMouse();
|
||||
else
|
||||
setMouse(widget);
|
||||
}
|
||||
|
||||
// Mouse movement
|
||||
if (mousemove) {
|
||||
Widget* dst;
|
||||
|
||||
// Reset double click status
|
||||
double_click_level = DOUBLE_CLICK_NONE;
|
||||
|
||||
if (capture_widget)
|
||||
dst = capture_widget;
|
||||
else
|
||||
dst = mouse_widget;
|
||||
|
||||
// Send the mouse movement message
|
||||
enqueueMessage(newMouseMessage(kMouseMoveMessage, dst,
|
||||
currentMouseButtons(0)));
|
||||
generateSetCursorMessage();
|
||||
}
|
||||
}
|
||||
if (mousemove || !mouse_widget)
|
||||
handleMouseMove(mousePos, currentMouseButtons(0));
|
||||
|
||||
// Mouse wheel
|
||||
if (jmouse_z(0) != jmouse_z(1)) {
|
||||
enqueueMessage(newMouseMessage(kMouseWheelMessage,
|
||||
capture_widget ? capture_widget:
|
||||
mouse_widget,
|
||||
currentMouseButtons(0)));
|
||||
}
|
||||
if (jmouse_z(0) != jmouse_z(1))
|
||||
handleMouseWheel(mousePos, currentMouseButtons(0), jmouse_z(0) - jmouse_z(1));
|
||||
|
||||
// Mouse clicks
|
||||
if (jmouse_b(0) != jmouse_b(1)) {
|
||||
@ -359,63 +354,34 @@ bool Manager::generateMessages()
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Z order: Send the window to top (only when you click in
|
||||
// a window that aren't the desktop).
|
||||
if (msgType == kMouseDownMessage && !capture_widget && mouse_widget) {
|
||||
// The clicked window
|
||||
Window* window = mouse_widget->getRoot();
|
||||
Manager* win_manager = (window ? window->getManager(): NULL);
|
||||
|
||||
if ((window) &&
|
||||
// We cannot change Z-order of desktop windows
|
||||
(!window->isDesktop()) &&
|
||||
// We cannot change Z order of foreground windows because a
|
||||
// foreground window can launch other background windows
|
||||
// which should be kept on top of the foreground one.
|
||||
(!window->isForeground()) &&
|
||||
// If the window is not already the top window of the manager.
|
||||
(window != win_manager->getTopWindow())) {
|
||||
base::ScopedValue<Widget*> scoped(m_lockedWindow, window, NULL);
|
||||
|
||||
// Put it in the top of the list
|
||||
win_manager->removeChild(window);
|
||||
|
||||
if (window->isOnTop())
|
||||
win_manager->insertChild(0, window);
|
||||
else {
|
||||
int pos = (int)win_manager->getChildren().size();
|
||||
UI_FOREACH_WIDGET_BACKWARD(win_manager->getChildren(), it) {
|
||||
if (static_cast<Window*>(*it)->isOnTop())
|
||||
break;
|
||||
|
||||
--pos;
|
||||
}
|
||||
win_manager->insertChild(pos, window);
|
||||
}
|
||||
|
||||
window->invalidate();
|
||||
}
|
||||
|
||||
// Put the focus
|
||||
setFocus(mouse_widget);
|
||||
switch (msgType) {
|
||||
case kMouseDownMessage:
|
||||
handleMouseDown(mousePos, mouseButtons);
|
||||
break;
|
||||
case kMouseUpMessage:
|
||||
handleMouseUp(mousePos, mouseButtons);
|
||||
break;
|
||||
case kDoubleClickMessage:
|
||||
handleMouseDoubleClick(mousePos, mouseButtons);
|
||||
break;
|
||||
}
|
||||
|
||||
enqueueMessage(newMouseMessage(msgType,
|
||||
capture_widget ? capture_widget:
|
||||
mouse_widget,
|
||||
mouseButtons));
|
||||
}
|
||||
}
|
||||
|
||||
// Generate Close message when the user press close button on the system window.
|
||||
if (want_close_stage == STAGE_WANT_CLOSE) {
|
||||
want_close_stage = STAGE_NORMAL;
|
||||
|
||||
Message* msg = new Message(kCloseAppMessage);
|
||||
msg->broadcastToChildren(this);
|
||||
enqueueMessage(msg);
|
||||
}
|
||||
void Manager::generateSetCursorMessage(const gfx::Point& mousePos)
|
||||
{
|
||||
Widget* dst = (capture_widget ? capture_widget: mouse_widget);
|
||||
if (dst)
|
||||
enqueueMessage(newMouseMessage(kSetCursorMessage, dst,
|
||||
mousePos, currentMouseButtons(0)));
|
||||
else
|
||||
jmouse_set_cursor(kArrowCursor);
|
||||
}
|
||||
|
||||
void Manager::generateKeyMessages()
|
||||
{
|
||||
// Generate kKeyDownMessage messages.
|
||||
int c;
|
||||
while (keypressed()) {
|
||||
int scancode;
|
||||
int unicode_char = ureadkey(&scancode);
|
||||
@ -435,7 +401,7 @@ bool Manager::generateMessages()
|
||||
enqueueMessage(msg);
|
||||
}
|
||||
|
||||
for (c=0; c<KEY_MAX; c++) {
|
||||
for (int c=0; c<KEY_MAX; c++) {
|
||||
if (old_readed_key[c] != key[c]) {
|
||||
KeyScancode scancode = static_cast<ui::KeyScancode>(c);
|
||||
|
||||
@ -466,7 +432,20 @@ bool Manager::generateMessages()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static MouseButtons mouse_buttons_from_she_to_ui(const she::Event& sheEvent)
|
||||
{
|
||||
switch (sheEvent.button()) {
|
||||
case she::Event::LeftButton: return kButtonLeft; break;
|
||||
case she::Event::RightButton: return kButtonRight; break;
|
||||
case she::Event::MiddleButton: return kButtonMiddle; break;
|
||||
default: return kButtonNone;
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::generateMessagesFromSheEvents()
|
||||
{
|
||||
// Events from "she" layer.
|
||||
she::Event sheEvent;
|
||||
for (;;) {
|
||||
@ -476,34 +455,179 @@ bool Manager::generateMessages()
|
||||
|
||||
switch (sheEvent.type()) {
|
||||
|
||||
case she::Event::DropFiles:
|
||||
{
|
||||
Message* msg = new DropFilesMessage(sheEvent.files());
|
||||
msg->addRecipient(this);
|
||||
enqueueMessage(msg);
|
||||
}
|
||||
case she::Event::DropFiles: {
|
||||
Message* msg = new DropFilesMessage(sheEvent.files());
|
||||
msg->addRecipient(this);
|
||||
enqueueMessage(msg);
|
||||
break;
|
||||
}
|
||||
|
||||
case she::Event::MouseMove: {
|
||||
if (!mouse_events_from_she)
|
||||
continue;
|
||||
|
||||
_internal_set_mouse_position(sheEvent.position());
|
||||
|
||||
handleMouseMove(sheEvent.position(), m_mouseButtons);
|
||||
break;
|
||||
}
|
||||
|
||||
case she::Event::MouseDown: {
|
||||
if (!mouse_events_from_she)
|
||||
continue;
|
||||
|
||||
MouseButtons pressedButton = mouse_buttons_from_she_to_ui(sheEvent);
|
||||
m_mouseButtons = (MouseButtons)((int)m_mouseButtons | (int)pressedButton);
|
||||
_internal_set_mouse_buttons(m_mouseButtons);
|
||||
|
||||
handleMouseDown(sheEvent.position(), pressedButton);
|
||||
break;
|
||||
}
|
||||
|
||||
case she::Event::MouseUp: {
|
||||
if (!mouse_events_from_she)
|
||||
continue;
|
||||
|
||||
MouseButtons releasedButton = mouse_buttons_from_she_to_ui(sheEvent);
|
||||
m_mouseButtons = (MouseButtons)((int)m_mouseButtons & ~(int)releasedButton);
|
||||
_internal_set_mouse_buttons(m_mouseButtons);
|
||||
|
||||
handleMouseUp(sheEvent.position(), releasedButton);
|
||||
break;
|
||||
}
|
||||
|
||||
case she::Event::MouseDoubleClick: {
|
||||
if (!mouse_events_from_she)
|
||||
continue;
|
||||
|
||||
MouseButtons clickedButton = mouse_buttons_from_she_to_ui(sheEvent);
|
||||
handleMouseUp(sheEvent.position(), clickedButton);
|
||||
break;
|
||||
}
|
||||
|
||||
case she::Event::MouseWheel: {
|
||||
if (!mouse_events_from_she)
|
||||
continue;
|
||||
|
||||
handleMouseWheel(sheEvent.position(), m_mouseButtons, sheEvent.delta());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate messages for timers
|
||||
Timer::pollTimers();
|
||||
void Manager::handleMouseMove(const gfx::Point& mousePos, MouseButtons mouseButtons)
|
||||
{
|
||||
// Get the list of widgets to send mouse messages.
|
||||
mouse_widgets_list.clear();
|
||||
broadcastMouseMessage(mouse_widgets_list);
|
||||
|
||||
// Generate redraw events.
|
||||
flushRedraw();
|
||||
// Get the widget under the mouse
|
||||
Widget* widget = NULL;
|
||||
UI_FOREACH_WIDGET(mouse_widgets_list, it) {
|
||||
widget = (*it)->pick(mousePos);
|
||||
if (widget)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!msg_queue.empty())
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
// Fixup "mouse" flag
|
||||
if (widget != mouse_widget) {
|
||||
if (!widget)
|
||||
freeMouse();
|
||||
else
|
||||
setMouse(widget);
|
||||
}
|
||||
|
||||
// Reset double click status
|
||||
double_click_level = DOUBLE_CLICK_NONE;
|
||||
|
||||
// Send the mouse movement message
|
||||
Widget* dst = (capture_widget ? capture_widget: mouse_widget);
|
||||
enqueueMessage(newMouseMessage(kMouseMoveMessage, dst, mousePos, mouseButtons));
|
||||
|
||||
generateSetCursorMessage(mousePos);
|
||||
}
|
||||
|
||||
void Manager::handleMouseDown(const gfx::Point& mousePos, MouseButtons mouseButtons)
|
||||
{
|
||||
handleWindowZOrder();
|
||||
|
||||
enqueueMessage(newMouseMessage(kMouseDownMessage,
|
||||
(capture_widget ? capture_widget: mouse_widget),
|
||||
mousePos, mouseButtons));
|
||||
}
|
||||
|
||||
void Manager::handleMouseUp(const gfx::Point& mousePos, MouseButtons mouseButtons)
|
||||
{
|
||||
enqueueMessage(newMouseMessage(kMouseUpMessage,
|
||||
(capture_widget ? capture_widget: mouse_widget),
|
||||
mousePos, mouseButtons));
|
||||
}
|
||||
|
||||
void Manager::handleMouseDoubleClick(const gfx::Point& mousePos, MouseButtons mouseButtons)
|
||||
{
|
||||
enqueueMessage(newMouseMessage(kDoubleClickMessage,
|
||||
(capture_widget ? capture_widget: mouse_widget),
|
||||
mousePos, mouseButtons));
|
||||
}
|
||||
|
||||
void Manager::handleMouseWheel(const gfx::Point& mousePos, MouseButtons mouseButtons, int delta)
|
||||
{
|
||||
enqueueMessage(newMouseMessage(kMouseWheelMessage,
|
||||
(capture_widget ? capture_widget: mouse_widget),
|
||||
mousePos, mouseButtons, delta));
|
||||
}
|
||||
|
||||
// Handles Z order: Send the window to top (only when you click in a
|
||||
// window that aren't the desktop).
|
||||
void Manager::handleWindowZOrder()
|
||||
{
|
||||
if (capture_widget || !mouse_widget)
|
||||
return;
|
||||
|
||||
// The clicked window
|
||||
Window* window = mouse_widget->getRoot();
|
||||
Manager* win_manager = (window ? window->getManager(): NULL);
|
||||
|
||||
if ((window) &&
|
||||
// We cannot change Z-order of desktop windows
|
||||
(!window->isDesktop()) &&
|
||||
// We cannot change Z order of foreground windows because a
|
||||
// foreground window can launch other background windows
|
||||
// which should be kept on top of the foreground one.
|
||||
(!window->isForeground()) &&
|
||||
// If the window is not already the top window of the manager.
|
||||
(window != win_manager->getTopWindow())) {
|
||||
base::ScopedValue<Widget*> scoped(m_lockedWindow, window, NULL);
|
||||
|
||||
// Put it in the top of the list
|
||||
win_manager->removeChild(window);
|
||||
|
||||
if (window->isOnTop())
|
||||
win_manager->insertChild(0, window);
|
||||
else {
|
||||
int pos = (int)win_manager->getChildren().size();
|
||||
UI_FOREACH_WIDGET_BACKWARD(win_manager->getChildren(), it) {
|
||||
if (static_cast<Window*>(*it)->isOnTop())
|
||||
break;
|
||||
|
||||
--pos;
|
||||
}
|
||||
win_manager->insertChild(pos, window);
|
||||
}
|
||||
|
||||
window->invalidate();
|
||||
}
|
||||
|
||||
// Put the focus
|
||||
setFocus(mouse_widget);
|
||||
}
|
||||
|
||||
void Manager::dispatchMessages()
|
||||
{
|
||||
// Add the "Queue Processing" message for the manager.
|
||||
enqueueMessage(newMouseMessage(kQueueProcessingMessage, this,
|
||||
currentMouseButtons(0)));
|
||||
gfx::Point(jmouse_x(0), jmouse_y(0)), currentMouseButtons(0)));
|
||||
|
||||
pumpQueue();
|
||||
}
|
||||
@ -716,7 +840,7 @@ void Manager::setMouse(Widget* widget)
|
||||
it = widget_parents.begin();
|
||||
|
||||
Message* msg = newMouseMessage(kMouseEnterMessage, NULL,
|
||||
currentMouseButtons(0));
|
||||
gfx::Point(jmouse_x(0), jmouse_y(0)), currentMouseButtons(0));
|
||||
|
||||
for (; it != widget_parents.end(); ++it) {
|
||||
(*it)->flags |= JI_HASMOUSE;
|
||||
@ -724,7 +848,7 @@ void Manager::setMouse(Widget* widget)
|
||||
}
|
||||
|
||||
enqueueMessage(msg);
|
||||
generateSetCursorMessage();
|
||||
generateSetCursorMessage(gfx::Point(jmouse_x(0), jmouse_y(0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1224,22 +1348,6 @@ void Manager::collectGarbage()
|
||||
Internal routines
|
||||
**********************************************************************/
|
||||
|
||||
// static
|
||||
void Manager::generateSetCursorMessage()
|
||||
{
|
||||
Widget* dst;
|
||||
if (capture_widget)
|
||||
dst = capture_widget;
|
||||
else
|
||||
dst = mouse_widget;
|
||||
|
||||
if (dst)
|
||||
enqueueMessage(newMouseMessage(kSetCursorMessage, dst,
|
||||
currentMouseButtons(0)));
|
||||
else
|
||||
jmouse_set_cursor(kArrowCursor);
|
||||
}
|
||||
|
||||
// static
|
||||
void Manager::removeWidgetFromRecipients(Widget* widget, Message* msg)
|
||||
{
|
||||
@ -1276,13 +1384,10 @@ Widget* Manager::findMagneticWidget(Widget* widget)
|
||||
}
|
||||
|
||||
// static
|
||||
Message* Manager::newMouseMessage(MessageType type, Widget* widget,
|
||||
MouseButtons buttons)
|
||||
Message* Manager::newMouseMessage(MessageType type,
|
||||
Widget* widget, gfx::Point mousePos, MouseButtons buttons, int delta)
|
||||
{
|
||||
Message* msg =
|
||||
new MouseMessage(type, buttons,
|
||||
gfx::Point(jmouse_x(0),
|
||||
jmouse_y(0)));
|
||||
Message* msg = new MouseMessage(type, buttons, mousePos, delta);
|
||||
|
||||
if (widget != NULL)
|
||||
msg->addRecipient(widget);
|
||||
|
@ -92,14 +92,23 @@ namespace ui {
|
||||
virtual LayoutIO* onGetLayoutIO();
|
||||
|
||||
private:
|
||||
void generateMouseMessages();
|
||||
void generateSetCursorMessage(const gfx::Point& mousePos);
|
||||
void generateKeyMessages();
|
||||
void generateMessagesFromSheEvents();
|
||||
void handleMouseMove(const gfx::Point& mousePos, MouseButtons mouseButtons);
|
||||
void handleMouseDown(const gfx::Point& mousePos, MouseButtons mouseButtons);
|
||||
void handleMouseUp(const gfx::Point& mousePos, MouseButtons mouseButtons);
|
||||
void handleMouseDoubleClick(const gfx::Point& mousePos, MouseButtons mouseButtons);
|
||||
void handleMouseWheel(const gfx::Point& mousePos, MouseButtons mouseButtons, int delta);
|
||||
void handleWindowZOrder();
|
||||
|
||||
void pumpQueue();
|
||||
void generateSetCursorMessage();
|
||||
static void removeWidgetFromRecipients(Widget* widget, Message* msg);
|
||||
static bool someParentIsFocusStop(Widget* widget);
|
||||
static Widget* findMagneticWidget(Widget* widget);
|
||||
static Message* newMouseMessage(MessageType type, Widget* destination);
|
||||
static Message* newMouseMessage(MessageType type, Widget* destination,
|
||||
MouseButtons mouseButtons);
|
||||
static Message* newMouseMessage(MessageType type,
|
||||
Widget* widget, gfx::Point mousePos, MouseButtons buttons, int delta = 0);
|
||||
static MouseButtons currentMouseButtons(int antique);
|
||||
void broadcastKeyMsg(Message* msg);
|
||||
|
||||
@ -113,6 +122,9 @@ namespace ui {
|
||||
// This member is used to make freeWidget() a no-op when we
|
||||
// restack a window if the user clicks on it.
|
||||
Widget* m_lockedWindow;
|
||||
|
||||
// Current pressed buttons.
|
||||
MouseButtons m_mouseButtons;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
@ -101,20 +101,22 @@ namespace ui {
|
||||
class MouseMessage : public Message
|
||||
{
|
||||
public:
|
||||
MouseMessage(MessageType type, MouseButtons buttons, const gfx::Point& pos)
|
||||
: Message(type), m_buttons(buttons), m_pos(pos) {
|
||||
MouseMessage(MessageType type, MouseButtons buttons, const gfx::Point& pos, int delta)
|
||||
: Message(type), m_buttons(buttons), m_pos(pos), m_delta(delta) {
|
||||
}
|
||||
|
||||
MouseButtons buttons() const { return m_buttons; }
|
||||
bool left() const { return (m_buttons & kButtonLeft) == kButtonLeft; }
|
||||
bool right() const { return (m_buttons & kButtonRight) == kButtonRight; }
|
||||
bool middle() const { return (m_buttons & kButtonMiddle) == kButtonMiddle; }
|
||||
int wheelDelta() const { return m_delta; }
|
||||
|
||||
const gfx::Point& position() const { return m_pos; }
|
||||
|
||||
private:
|
||||
MouseButtons m_buttons; // Pressed buttons
|
||||
gfx::Point m_pos; // Mouse position
|
||||
int m_delta; // Wheel axis variation
|
||||
};
|
||||
|
||||
class TimerMessage : public Message
|
||||
|
@ -191,7 +191,7 @@ bool Slider::onProcessMessage(Message* msg)
|
||||
|
||||
case kMouseWheelMessage:
|
||||
if (isEnabled()) {
|
||||
int value = m_value + jmouse_z(0) - jmouse_z(1);
|
||||
int value = m_value + static_cast<MouseMessage*>(msg)->wheelDelta();
|
||||
|
||||
value = MID(m_min, value, m_max);
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include "ui/widget.h"
|
||||
|
||||
#include <allegro.h>
|
||||
#if defined(ALLEGRO_WINDOWS)
|
||||
#if defined(WIN32)
|
||||
#include <winalleg.h>
|
||||
#elif defined(ALLEGRO_UNIX)
|
||||
#include <xalleg.h>
|
||||
@ -46,6 +46,7 @@ volatile int ji_clock = 0;
|
||||
|
||||
static CursorType mouse_cursor_type = kNoCursor;
|
||||
static Cursor* mouse_cursor = NULL;
|
||||
static she::Display* mouse_display = NULL;
|
||||
static Overlay* mouse_cursor_overlay = NULL;
|
||||
|
||||
/* Mouse information (button and position). */
|
||||
@ -125,6 +126,7 @@ void SetDisplay(she::Display* display)
|
||||
CursorType cursor = jmouse_get_cursor();
|
||||
|
||||
jmouse_set_cursor(kNoCursor);
|
||||
mouse_display = display;
|
||||
ji_screen = (display ? reinterpret_cast<BITMAP*>(display->getSurface()->nativeHandle()): NULL);
|
||||
ji_screen_w = (ji_screen ? ji_screen->w: 0);
|
||||
ji_screen_h = (ji_screen ? ji_screen->h: 0);
|
||||
@ -240,6 +242,21 @@ bool jmouse_poll()
|
||||
return false;
|
||||
}
|
||||
|
||||
void _internal_set_mouse_position(const gfx::Point& newPos)
|
||||
{
|
||||
moved = true;
|
||||
m_x[1] = m_x[0];
|
||||
m_y[1] = m_y[0];
|
||||
m_x[0] = newPos.x;
|
||||
m_y[0] = newPos.y;
|
||||
}
|
||||
|
||||
void _internal_set_mouse_buttons(MouseButtons buttons)
|
||||
{
|
||||
m_b[1] = m_b[0];
|
||||
m_b[0] = buttons;
|
||||
}
|
||||
|
||||
gfx::Point get_mouse_position()
|
||||
{
|
||||
return gfx::Point(jmouse_x(0), jmouse_y(0));
|
||||
@ -345,8 +362,8 @@ static void update_mouse_position()
|
||||
m_y[0] = JI_SCREEN_H * mouse_y / SCREEN_H;
|
||||
|
||||
if (is_windowed_mode()) {
|
||||
#ifdef ALLEGRO_WINDOWS
|
||||
// This help us (in windows) to get mouse feedback when we capture
|
||||
#ifdef WIN32
|
||||
// This help us (on Windows) to get mouse feedback when we capture
|
||||
// the mouse but we are outside the window.
|
||||
POINT pt;
|
||||
RECT rc;
|
||||
|
@ -57,6 +57,9 @@ namespace ui {
|
||||
|
||||
bool jmouse_poll();
|
||||
|
||||
void _internal_set_mouse_position(const gfx::Point& newPos);
|
||||
void _internal_set_mouse_buttons(MouseButtons buttons);
|
||||
|
||||
gfx::Point get_mouse_position();
|
||||
void set_mouse_position(const gfx::Point& newPos);
|
||||
|
||||
|
@ -134,7 +134,7 @@ bool TextBox::onProcessMessage(Message* msg)
|
||||
if (view) {
|
||||
gfx::Point scroll = view->getViewScroll();
|
||||
|
||||
scroll.y += (jmouse_z(1) - jmouse_z(0)) * getTextHeight()*3;
|
||||
scroll.y += -static_cast<MouseMessage*>(msg)->wheelDelta() * getTextHeight()*3;
|
||||
|
||||
view->setViewScroll(scroll);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user