#lang racket/base (require racket/class ffi/unsafe "../../syntax.rkt" "../../lock.rkt" "../common/event.rkt" "item.rkt" "utils.rkt" "const.rkt" "window.rkt" "panel.rkt" "wndclass.rkt" "types.rkt") (provide (protect-out tab-panel%)) (define TCIF_TEXT #x0001) (define TCM_SETUNICODEFORMAT #x2005) (define TCM_FIRST #x1300) (define TCM_INSERTITEMW (+ TCM_FIRST 62)) (define TCM_SETITEMW (+ TCM_FIRST 61)) (define TCM_SETCURSEL (+ TCM_FIRST 12)) (define TCM_GETCURSEL (+ TCM_FIRST 11)) (define TCM_GETITEMCOUNT (+ TCM_FIRST 4)) (define TCM_DELETEITEM (+ TCM_FIRST 8)) (define TCM_DELETEALLITEMS (+ TCM_FIRST 9)) (define TCM_GETCURFOCUS (+ TCM_FIRST 47)) (define TCM_SETCURFOCUS (+ TCM_FIRST 48)) (define-cstruct _TCITEMW ([mask _UINT] [dwState _DWORD] [dwStateMask _DWORD] [pszText _permanent-string/utf-16] [cchTextMax _int] [iImage _int] [lParam _LPARAM])) (define tab-panel% (class (item-mixin (panel-mixin window%)) (init parent x y w h style choices) (define callback void) (inherit auto-size set-control-font is-shown-to-root?) (define hwnd (CreateWindowExW/control 0 "PLTSysTabControl32" "" (bitwise-ior WS_CHILD WS_CLIPSIBLINGS) 0 0 0 0 (send parent get-content-hwnd) #f hInstance #f)) (define client-hwnd (CreateWindowExW 0 "PLTTabPanel" #f (bitwise-ior WS_CHILD WS_VISIBLE) 0 0 w h hwnd #f hInstance #f)) (super-new [callback (lambda (c) (callback c))] [extra-hwnds (list client-hwnd)] [parent parent] [hwnd hwnd] [style style]) (define/override (get-client-hwnd) client-hwnd) (SendMessageW hwnd TCM_SETUNICODEFORMAT 1 0) (define/private (with-item proc) (atomically (let ([item (cast (malloc _TCITEMW 'raw) _pointer _TCITEMW-pointer)]) (set-TCITEMW-mask! item TCIF_TEXT) (proc item (lambda () (free (TCITEMW-pszText item))) (lambda (msg w) (SendMessageW hwnd msg w (cast item _pointer _LPARAM)))) (free item)))) (set choices) (define tab-height 0) (set-control-font #f) (auto-size #f (if (null? choices) '("Choice") choices) 0 0 0 0 #:combine-width + (lambda (w h) (set! tab-height (+ h 6)) (set-size -11111 -11111 (+ w (* 6 (length choices))) (+ h 12)))) (define/override (set-size x y w h) (super set-size x y w h) (unless (or (= w -1) (= h -1)) (MoveWindow client-hwnd 1 (+ tab-height 2) (- w 4) (- h tab-height 6) #t))) (define/override (is-command? cmd) (= cmd -551)) (define/override (do-command cmd control-hwnd) (queue-window-event this (lambda () (callback this (new control-event% [event-type 'tab-panel] [time-stamp (current-milliseconds)]))))) ;; Needed after some actions: (define/private (refresh) (InvalidateRect hwnd #f #f)) (define/public (set-label pos str) (with-item (lambda (item done-str send-msg) (set-TCITEMW-pszText! item str) (send-msg TCM_SETITEMW pos) (done-str))) (refresh)) (define/public (set-selection pos) (SendMessageW hwnd TCM_SETCURSEL pos 0) (refresh)) (define/public (get-selection) (SendMessageW hwnd TCM_GETCURSEL 0 0)) (define/public (number) (SendMessageW hwnd TCM_GETITEMCOUNT 0 0)) (define/public (delete pos) (SendMessageW hwnd TCM_DELETEITEM pos 0) (refresh)) (public [append* append]) (define (append* str) (with-item (lambda (item done-str send-msg) (set-TCITEMW-pszText! item str) (send-msg TCM_INSERTITEMW (number)) (done-str))) (refresh)) (define/public (set choices) (let ([sel (get-selection)]) (SendMessageW hwnd TCM_DELETEALLITEMS 0 0) (with-item (lambda (item done-str send-msg) (for ([str (in-list choices)] [pos (in-naturals)]) (set-TCITEMW-pszText! item str) (send-msg TCM_INSERTITEMW pos) (done-str)))) (let ([sel (max 0 (min (length choices) sel))]) (set-selection sel)))) (define/override (gets-focus?) #t) (define/public (button-focus i) (if (= i -1) (SendMessageW hwnd TCM_GETCURFOCUS 0 0) (SendMessageW hwnd TCM_SETCURFOCUS i 0))) (define/public (set-callback cb) (set! callback cb))))