popup menus

This commit is contained in:
Matthew Flatt 2010-07-28 10:14:54 -05:00
parent 82c0a1cc29
commit bc7d3d7376
6 changed files with 174 additions and 52 deletions

View File

@ -3,10 +3,11 @@
scheme/foreign scheme/foreign
(only-in scheme/list drop take) (only-in scheme/list drop take)
ffi/objc ffi/objc
"../../syntax.rkt" "../common/event.rkt"
"utils.rkt" "../../syntax.rkt"
"types.rkt" "utils.rkt"
"window.rkt") "types.rkt"
"window.rkt")
(unsafe!) (unsafe!)
(objc-unsafe!) (objc-unsafe!)
@ -28,7 +29,7 @@
(define cocoa #f) (define cocoa #f)
(define cocoa-menu #f) (define cocoa-menu #f)
(define/public (install cocoa-parent label) (define/public (create-menu label)
(unless cocoa (unless cocoa
(set! cocoa (set! cocoa
(as-objc-allocation (as-objc-allocation
@ -46,16 +47,42 @@
(if item (if item
(send (mitem-item item) install cocoa-menu) (send (mitem-item item) install cocoa-menu)
(tellv cocoa-menu addItem: (tell NSMenuItem separatorItem)))) (tellv cocoa-menu addItem: (tell NSMenuItem separatorItem))))
items)) items)))
(define/public (install cocoa-parent label)
(create-menu label)
(tellv cocoa-parent addItem: cocoa)) (tellv cocoa-parent addItem: cocoa))
(define popup-box #f)
(define/public (do-popup v x y queue-cb)
(unless (null? items)
(create-menu "menu")
(let ([b (box #f)])
(set! popup-box b)
(tellv cocoa-menu
popUpMenuPositioningItem: (tell cocoa-menu itemAtIndex: #:type _NSUInteger 0)
atLocation: #:type _NSPoint (make-NSPoint x y)
inView: v)
(set! popup-box #f)
(let* ([i (unbox b)]
[e (new popup-event% [event-type 'menu-popdown])])
(send e set-menu-id i)
(queue-cb (lambda () (callback this e)))))))
(define/public (item-selected menu-item) (define/public (item-selected menu-item)
;; called in Cocoa thread ;; called in Cocoa thread
(let ([top (get-top-parent)]) (cond
(when top [popup-box
(queue-window-event (set-box! popup-box menu-item)]
top [(parent . is-a? . menu%)
(lambda () (send top on-menu-command menu-item)))))) (send parent item-selected menu-item)]
[else
(let ([top (get-top-parent)])
(when top
(queue-window-event
top
(lambda () (send top on-menu-command menu-item)))))]))
(define parent #f) (define parent #f)
(define/public (set-parent p) (set! parent p)) (define/public (set-parent p) (set! parent p))

View File

@ -40,10 +40,10 @@
(define-objc-mixin (KeyMouseResponder Superclass) (define-objc-mixin (KeyMouseResponder Superclass)
[wx] [wx]
[-a _void (mouseDown: [_id event]) [-a _void (mouseDown: [_id event])
(unless (do-mouse-event wx event 'left-down #t #f #f) (unless (do-mouse-event wx event 'left-down #t #f #f 'right-down)
(super-tell #:type _void mouseDown: event))] (super-tell #:type _void mouseDown: event))]
[-a _void (mouseUp: [_id event]) [-a _void (mouseUp: [_id event])
(unless (do-mouse-event wx event 'left-up #f #f #f) (unless (do-mouse-event wx event 'left-up #f #f #f 'right-up)
(super-tell #:type _void mouseUp: event))] (super-tell #:type _void mouseUp: event))]
[-a _void (mouseDragged: [_id event]) [-a _void (mouseDragged: [_id event])
(unless (do-mouse-event wx event 'motion #t #f #f) (unless (do-mouse-event wx event 'motion #t #f #f)
@ -112,20 +112,20 @@
(lambda () (send wx dispatch-on-char k #t)) (lambda () (send wx dispatch-on-char k #t))
#t)))))) #t))))))
(define (do-mouse-event wx event kind l? m? r?) (define (do-mouse-event wx event kind l? m? r? [ctl-kind kind])
(let* ([modifiers (tell #:type _NSUInteger event modifierFlags)] (let* ([modifiers (tell #:type _NSUInteger event modifierFlags)]
[bit? (lambda (m b) (positive? (bitwise-and m b)))] [bit? (lambda (m b) (positive? (bitwise-and m b)))]
[pos (tell #:type _NSPoint event locationInWindow)]) [pos (tell #:type _NSPoint event locationInWindow)])
(let-values ([(x y) (send wx window-point-to-view pos)]) (let-values ([(x y) (send wx window-point-to-view pos)]
[(control-down) (bit? modifiers NSControlKeyMask)])
(let ([m (new mouse-event% (let ([m (new mouse-event%
[event-type kind] [event-type (if control-down ctl-kind kind)]
[left-down l?] [left-down (and l? (not control-down))]
[middle-down m?] [middle-down m?]
[right-down r?] [right-down (or r? (and l? control-down))]
[x (->long x)] [x (->long x)]
[y (->long y)] [y (->long y)]
[shift-down (bit? modifiers NSShiftKeyMask)] [shift-down (bit? modifiers NSShiftKeyMask)]
[control-down (bit? modifiers NSControlKeyMask)]
[meta-down (bit? modifiers NSCommandKeyMask)] [meta-down (bit? modifiers NSCommandKeyMask)]
[alt-down (bit? modifiers NSAlternateKeyMask)] [alt-down (bit? modifiers NSAlternateKeyMask)]
[time-stamp (->long (* (tell #:type _double event timestamp) 1000.0))] [time-stamp (->long (* (tell #:type _double event timestamp) 1000.0))]
@ -312,7 +312,12 @@
(def/public-unimplemented on-drop-file) (def/public-unimplemented on-drop-file)
(def/public-unimplemented get-handle) (def/public-unimplemented get-handle)
(def/public-unimplemented set-phantom-size) (def/public-unimplemented set-phantom-size)
(def/public-unimplemented popup-menu)
(define/public (popup-menu m x y)
(send m do-popup (get-cocoa-content) x (flip-client y)
(lambda (thunk)
(queue-window-event this thunk))))
(define/public (center a b) (void)) (define/public (center a b) (void))
(def/public-unimplemented refresh) (def/public-unimplemented refresh)

View File

@ -91,7 +91,8 @@
(init-properties [[(symbol-in button check-box choice (init-properties [[(symbol-in button check-box choice
list-box list-box-dclick text-field list-box list-box-dclick text-field
text-field-enter slider radio-box text-field-enter slider radio-box
menu-popdown menu-popdown-none tab-panel) menu-popdown menu-popdown-none tab-panel
menu)
event-type] event-type]
;; FIXME: should have no default ;; FIXME: should have no default
'button]) 'button])
@ -99,7 +100,8 @@
(super-new [time-stamp time-stamp])) (super-new [time-stamp time-stamp]))
(defclass popup-event% control-event% (defclass popup-event% control-event%
(properties [[any? menu-id] 0])) (properties [[any? menu-id] 0])
(super-new))
(defclass scroll-event% event% (defclass scroll-event% event%
(init-properties [[(symbol-in top bottom line-up line-down page-up page-down thumb) event-type] (init-properties [[(symbol-in top bottom line-up line-down page-up page-down thumb) event-type]

View File

@ -27,6 +27,9 @@
(define-gtk gtk_window_maximize (_fun _GtkWidget -> _void)) (define-gtk gtk_window_maximize (_fun _GtkWidget -> _void))
(define-gtk gtk_window_unmaximize (_fun _GtkWidget -> _void)) (define-gtk gtk_window_unmaximize (_fun _GtkWidget -> _void))
(define-gtk gtk_widget_set_uposition (_fun _GtkWidget _int _int -> _void)) (define-gtk gtk_widget_set_uposition (_fun _GtkWidget _int _int -> _void))
(define-gtk gtk_window_get_position (_fun _GtkWidget (x : (_ptr o _int)) (y : (_ptr o _int))
-> _void
-> (values x y)))
(define (handle-delete gtk) (define (handle-delete gtk)
(let ([wx (gtk->wx gtk)]) (let ([wx (gtk->wx gtk)])
@ -162,7 +165,9 @@
(pre-on-char w e)) (pre-on-char w e))
(define/override (client-to-screen x y) (define/override (client-to-screen x y)
(void)) (let-values ([(dx dy) (gtk_window_get_position gtk)])
(set-box! x (+ (unbox x) dx))
(set-box! y (+ (unbox y) dy))))
(def/public-unimplemented on-toolbar-click) (def/public-unimplemented on-toolbar-click)
(def/public-unimplemented on-menu-click) (def/public-unimplemented on-menu-click)

View File

@ -7,7 +7,8 @@
"types.rkt" "types.rkt"
"const.rkt" "const.rkt"
"utils.rkt" "utils.rkt"
"menu-bar.rkt") "menu-bar.rkt"
"../common/event.rkt")
(unsafe!) (unsafe!)
(provide menu%) (provide menu%)
@ -22,6 +23,14 @@
(define-gtk gtk_check_menu_item_get_active (_fun _GtkWidget -> _gboolean)) (define-gtk gtk_check_menu_item_get_active (_fun _GtkWidget -> _gboolean))
(define-gtk gtk_menu_item_set_label (_fun _GtkWidget _string -> _void)) (define-gtk gtk_menu_item_set_label (_fun _GtkWidget _string -> _void))
(define-gtk gtk_container_remove (_fun _GtkWidget _GtkWidget -> _void)) (define-gtk gtk_container_remove (_fun _GtkWidget _GtkWidget -> _void))
(define-gtk gtk_label_set_text_with_mnemonic (_fun _GtkWidget _string -> _void))
(define-gtk gtk_bin_get_child (_fun _GtkWidget -> _GtkWidget))
(define-gtk gtk_get_current_event_time (_fun -> _uint32))
(define-gtk gtk_menu_popup (_fun _GtkWidget _pointer _pointer
(_fun _GtkWidget _pointer _pointer _pointer -> _void)
_pointer _uint _uint32
-> _void))
(define-signal-handler connect-menu-item-activate "activate" (define-signal-handler connect-menu-item-activate "activate"
(_fun _GtkWidget -> _void) (_fun _GtkWidget -> _void)
@ -29,6 +38,12 @@
(let ([wx (gtk->wx gtk)]) (let ([wx (gtk->wx gtk)])
(send wx do-on-select)))) (send wx do-on-select))))
(define-signal-handler connect-menu-deactivate "deactivate"
(_fun _GtkWidget -> _void)
(lambda (gtk)
(let ([wx (gtk->wx gtk)])
(send wx do-no-selected))))
(define menu-item-handler% (define menu-item-handler%
(class widget% (class widget%
(init gtk) (init gtk)
@ -41,11 +56,7 @@
(define/public (get-item) menu-item) (define/public (get-item) menu-item)
(define/public (do-on-select) (define/public (do-on-select)
(let ([top (send menu get-top-parent)]) (send menu do-selected menu-item))
(when top
(queue-window-event
top
(lambda () (send top on-menu-command menu-item))))))
(define/public (on-select) (define/public (on-select)
(send menu on-select-item menu-item)))) (send menu on-select-item menu-item))))
@ -55,11 +66,15 @@
callback callback
font) font)
(define cb callback)
(define gtk (gtk_menu_new)) (define gtk (gtk_menu_new))
(define/public (get-gtk) gtk) (define/public (get-gtk) gtk)
(super-new [gtk gtk]) (super-new [gtk gtk])
(connect-menu-deactivate gtk)
(define items null) (define items null)
(define parent #f) (define parent #f)
@ -72,6 +87,56 @@
(send parent get-top-parent) (send parent get-top-parent)
(send parent get-top-window)))) (send parent get-top-window))))
(define on-popup #f)
(define cancel-none-box (box #t))
(define/public (popup x y queue-cb)
(set! on-popup queue-cb)
(set! cancel-none-box (box #f))
(gtk_menu_popup gtk
#f
#f
(lambda (menu _x _y _push)
(ptr-set! _x _int x)
(ptr-set! _y _int y)
(ptr-set! _push _gboolean #t))
#f
0
(gtk_get_current_event_time)))
(define/public (do-selected menu-item)
;; Called in event-pump thread
(let ([top (get-top-parent)])
(cond
[top
(queue-window-event
top
(lambda () (send top on-menu-command menu-item)))]
[on-popup
(let* ([e (new popup-event% [event-type 'menu-popdown])]
[pu on-popup]
[cnb cancel-none-box])
(set! on-popup #f)
(set-box! cancel-none-box #t)
(send e set-menu-id menu-item)
(pu (lambda () (cb this e))))]
[parent (send parent do-selected menu-item)])))
(define/public (do-no-selected)
;; Queue a none-selected event, but only tentatively, because
;; the selection event may come later and cancel the none-selected
;; event.
(when on-popup
(let* ([e (new popup-event% [event-type 'menu-popdown])]
[pu on-popup]
[cnb cancel-none-box])
(send e set-menu-id #f)
(pu (lambda ()
(when (eq? on-popup pu)
(set! on-popup #f))
(unless (unbox cnb)
(cb this e)))))))
(define/private (adjust-shortcut item-gtk title) (define/private (adjust-shortcut item-gtk title)
(cond (cond
[(regexp-match #rx"\tCtrl[+](.)$" title) [(regexp-match #rx"\tCtrl[+](.)$" title)
@ -124,7 +189,8 @@
(define/public (set-label item str) (define/public (set-label item str)
(let ([gtk (find-gtk item)]) (let ([gtk (find-gtk item)])
(when gtk (when gtk
(gtk_menu_item_set_label gtk str)))) (gtk_label_set_text_with_mnemonic (gtk_bin_get_child gtk)
(fixup-mneumonic str)))))
(define/public (enable item on?) (define/public (enable item on?)
(let ([gtk (find-gtk item)]) (let ([gtk (find-gtk item)])

View File

@ -153,27 +153,37 @@
(GdkEventCrossing-state event) (GdkEventCrossing-state event)
(GdkEventButton-state event)))] (GdkEventButton-state event)))]
[bit? (lambda (m v) (positive? (bitwise-and m v)))] [bit? (lambda (m v) (positive? (bitwise-and m v)))]
[type (cond
[(= type GDK_MOTION_NOTIFY)
'motion]
[(= type GDK_ENTER_NOTIFY)
'enter]
[(= type GDK_LEAVE_NOTIFY)
'leave]
[(= type GDK_BUTTON_PRESS)
(case (GdkEventButton-button event)
[(1) 'left-down]
[(3) 'right-down]
[else 'middle-down])]
[else
(case (GdkEventButton-button event)
[(1) 'left-up]
[(3) 'right-up]
[else 'middle-up])])]
[m (new mouse-event% [m (new mouse-event%
[event-type (cond [event-type type]
[(= type GDK_MOTION_NOTIFY) [left-down (case type
'motion] [(left-down) #t]
[(= type GDK_ENTER_NOTIFY) [(left-up) #f]
'enter] [else (bit? modifiers GDK_BUTTON1_MASK)])]
[(= type GDK_LEAVE_NOTIFY) [middle-down (case type
'leave] [(middle-down) #t]
[(= type GDK_BUTTON_PRESS) [(middle-up) #f]
(case (GdkEventButton-button event) [else (bit? modifiers GDK_BUTTON2_MASK)])]
[(1) 'left-down] [right-down (case type
[(3) 'right-down] [(right-down) #t]
[else 'middle-down])] [(right-up) #f]
[else [else (bit? modifiers GDK_BUTTON3_MASK)])]
(case (GdkEventButton-button event)
[(1) 'left-up]
[(3) 'right-up]
[else 'middle-up])])]
[left-down (bit? modifiers GDK_BUTTON1_MASK)]
[middle-down (bit? modifiers GDK_BUTTON2_MASK)]
[right-down (bit? modifiers GDK_BUTTON2_MASK)]
[x (->long ((if motion? [x (->long ((if motion?
GdkEventMotion-x GdkEventMotion-x
(if crossing? GdkEventCrossing-x GdkEventButton-x)) (if crossing? GdkEventCrossing-x GdkEventButton-x))
@ -338,7 +348,14 @@
(def/public-unimplemented on-drop-file) (def/public-unimplemented on-drop-file)
(def/public-unimplemented get-handle) (def/public-unimplemented get-handle)
(def/public-unimplemented set-phantom-size) (def/public-unimplemented set-phantom-size)
(def/public-unimplemented popup-menu)
(define/public (popup-menu m x y)
(let ([gx (box x)]
[gy (box y)])
(client-to-screen gx gy)
(send m popup (unbox gx) (unbox gy)
(lambda (thunk) (queue-window-event this thunk)))))
(define/public (center a b) (void)) (define/public (center a b) (void))
(define/public (refresh) (void)) (define/public (refresh) (void))
@ -349,7 +366,7 @@
(set-box! x (- (unbox x) (unbox xb))) (set-box! x (- (unbox x) (unbox xb)))
(set-box! y (- (unbox y) (unbox yb))))) (set-box! y (- (unbox y) (unbox yb)))))
(define/public (client-to-screen x y) (define/public (client-to-screen x y)
(send parent screen-to-client x y) (send parent client-to-screen x y)
(set-box! x (+ (unbox x) save-x)) (set-box! x (+ (unbox x) save-x))
(set-box! y (+ (unbox y) save-y))) (set-box! y (+ (unbox y) save-y)))