Search code examples
user-interfacesmalltalkmousewheelsqueakmorphic

How to use the mousewheel in a Squeak / Morphic GUI


I am implementing a graphical user interface with Morphic / Squeak. Some of the items have drag & drop functionality. While dragging, I want to be able to rotate these items with the mousewheel.

The first problem is that using the mousewheel ends the drag-action and leads to a drop (attempt). How can I suppress that - and fire the mouseWheelEvent at the same time?

The second problem: How can I assign a mousewheel-event to my Morph? As mentioned above, this event only is relevant while dragging this Morph. (solved)


Solution

  • Appears that on VM implementations that have chosen to support it, Squeak maps the mouse wheel to Ctrl Up-Arrow and Ctrl-Down-Arrow key events. For instance, on Win32 in sqWin32Window.c:

    if( WM_MOUSEWHEEL == message || g_WM_MOUSEWHEEL == message ) {
        /* Record mouse wheel msgs as CTRL-Up/Down */
        short zDelta = (short) HIWORD(wParam);
        if(inputSemaphoreIndex) {
            sqKeyboardEvent *evt = (sqKeyboardEvent*) sqNextEventPut();
            evt->type = EventTypeKeyboard;
            evt->timeStamp = lastMessage->time;
            evt->charCode = (zDelta > 0) ? 30 : 31;
            evt->pressCode = EventKeyChar;
            evt->modifiers = CtrlKeyBit;
            evt->utf32Code = 0;
            evt->reserved1 = 0;
        } else {
            buttonState = 64;
            if (zDelta < 0) {
                recordVirtualKey(message,VK_DOWN,lParam);
            } else {
                recordVirtualKey(message,VK_UP,lParam);
            }
        }
        return 1;
    }
    

    So that's pretty much what you've got to work with inside Squeak. (If you're using the Polymorph extensions, there is a special mouseWheel event, but all they're doing is filtering Ctrl-Up and Ctrl-Down and generating a "fake" MouseWheelEvent message.)

    Looking at a bit of code for handleEvent in HandMorph:

    evt isMouse ifTrue:[
        self sendListenEvent: evt to: self mouseListeners.
        lastMouseEvent _ evt].
    
        "Check for pending drag or double click operations."
        mouseClickState ifNotNil:[
            (mouseClickState handleEvent: evt from: self) ifFalse:[
            "Possibly dispatched #click: or something and will not re-establish otherwise"
            ^self mouseOverHandler processMouseOver: lastMouseEvent]].
    
            evt isMove ifTrue:[
                self position: evt position.
                self sendMouseEvent: evt.
            ] ifFalse:[
                "Issue a synthetic move event if we're not at the position of the event"
                (evt position = self position) ifFalse:[self moveToEvent: evt].
                "Drop submorphs on button events"
                (self hasSubmorphs) 
                    ifTrue:[self dropMorphs: evt]
                    ifFalse:[self sendMouseEvent: evt].
            ].
    

    The Polymorph MouseWheelEvent is a subclass of MouseEvent that doesn't return true to isMove, hence you get a drop. You'll have to change something here if you want this to work.