diff --git a/example1/example.rkt b/example1/example.rkt index beec84b..e467f79 100644 --- a/example1/example.rkt +++ b/example1/example.rkt @@ -23,36 +23,34 @@ (define-runtime-path dialog-html "example-1-dialog.html") (define-runtime-path cur-dir ".") -#| -(define test-menu (menu 'main-menu - (menu-item 'm-file "File" - #:submenu - (menu (menu-item 'm-open "Open File") - (menu-item 'm-close "Close File") - (menu-item 'm-select-dir "Select Folder" #:separator #t) - (menu-item 'm-quit "Quit" #:separator #t))) - (menu-item 'm-edit "Edit" - #:submenu - (menu (menu-item 'm-copy "Copy") - (menu-item 'm-cut "Cut") - (menu-item 'm-paste "Paste") - (menu-item 'm-prefs "Preferences" #:separator #t) - )) - (menu-item 'm-auto "Processes" - #:submenu - (menu (menu-item 'm-start "Start counter") - (menu-item 'm-sub "Submenu" - #:submenu - (menu (menu-item 'm-sub1 "Submenu 1") - (menu-item 'm-sub2 "Submenu 2") - (menu-item 'm-sub3 "Submenu 3") - ) - ) - (menu-item 'm-stop "Stop counter") - ) - ) - )) -|# +(define test-menu (wv-menu 'main-menu + (wv-menu-item 'm-file "File" + #:submenu + (wv-menu (wv-menu-item 'm-open "Open File") + (wv-menu-item 'm-close "Close File") + (wv-menu-item 'm-select-dir "Select Folder" #:separator #t) + (wv-menu-item 'm-quit "Quit" #:separator #t))) + (wv-menu-item 'm-edit "Edit" + #:submenu + (wv-menu (wv-menu-item 'm-copy "Copy") + (wv-menu-item 'm-cut "Cut") + (wv-menu-item 'm-paste "Paste") + (wv-menu-item 'm-prefs "Preferences" #:separator #t) + )) + (wv-menu-item 'm-auto "Processes" + #:submenu + (wv-menu (wv-menu-item 'm-start "Start counter") + (wv-menu-item 'm-sub "Submenu" + #:submenu + (wv-menu (wv-menu-item 'm-sub1 "Submenu 1") + (wv-menu-item 'm-sub2 "Submenu 2") + (wv-menu-item 'm-sub3 "Submenu 3") + ) + ) + (wv-menu-item 'm-stop "Stop counter") + ) + ) + )) (define example-1-dialog% (class wv-dialog% @@ -222,7 +220,7 @@ ) (define/override (page-loaded oke) - (ww-debug (format "HTML LOADED ~a" oke)) + (ww-debug (format "HTML LOADED ~a ~a" oke (current-milliseconds))) (set! has-page oke) (super page-loaded oke) (displayln "super called") @@ -259,11 +257,13 @@ (λ (el evt data) (send this choose-dir*))) ) - (displayln "page-loaded done") - ) - - ;(ww-debug "SETTING MENU") - #|(let* ((div-open (send this element 'div-open)) + + (displayln (format "setting menu ~a" (current-milliseconds))) + (send this set-menu! test-menu) + (send this connect-menu! 'm-quit (λ () + (send this reset-counter) + (send this close))) + (let* ((div-open (send this element 'div-open)) (c-open 0) (div-close (send this element 'div-close)) (c-close 0) @@ -273,39 +273,29 @@ (c-cut 0) (div-paste (send this element 'div-paste)) (c-paste 0) + (mk (λ (item el str count) + (send this connect-menu! item + (λ () + (send el set-innerHTML! (format "~a ~a" str (count)))) + ) + ) + ) ) + (mk 'm-open div-open "Open file" (inc c-open)) + (mk 'm-close div-close "Close file" (inc c-close)) + (mk 'm-copy div-copy "Edit Copy" (inc c-copy)) + (mk 'm-cut div-cut "Edit Cut" (inc c-cut)) + (mk 'm-paste div-paste "Edit Paste" (inc c-paste)) + ) + + (send this connect-menu! 'm-start (λ () (send this start-counter))) + (send this connect-menu! 'm-stop (λ () (send this reset-counter))) + (send this connect-menu! 'm-prefs (λ () (send this prefs))) + (send this connect-menu! 'm-select-dir (λ () (send this choose-dir*))) - (send this set-menu! test-menu) - (send this connect-menu! 'm-quit - (λ () - (send this reset-counter) - (send this close)) - ) - (let ((make-menu-executor (λ (item elem string count) - (send this connect-menu! item - (λ () - (send elem set-inner-html! (format "~a ~a" string (count))))))) - ) - (make-menu-executor 'm-open div-open "Open file" (inc c-open)) - (make-menu-executor 'm-close div-close "Close file" (inc c-close)) - (make-menu-executor 'm-copy div-copy "Edit Copy" (inc c-copy)) - (make-menu-executor 'm-cut div-cut "Edit Cut" (inc c-cut)) - (make-menu-executor 'm-paste div-paste "Edit Paste" (inc c-paste)) - - (send this connect-menu! 'm-start - (λ () (send this start-counter))) - - (send this connect-menu! 'm-stop - (λ () (send this reset-counter))) - - (send this connect-menu! 'm-prefs - (λ () (send this prefs))) - - (send this connect-menu! 'm-select-dir - (λ () (send this choose-dir))) - - ) - )|# + + (displayln "page-loaded done") + ) (begin (displayln "Yes this works!") diff --git a/info.rkt b/info.rkt index b5d76ad..50e33af 100644 --- a/info.rkt +++ b/info.rkt @@ -1,18 +1,23 @@ #lang info (define pkg-authors '(hnmdijkema)) -(define version "0.2.20") +(define version "0.1.1") (define license 'MIT) (define collection "racket-webview") (define pkg-desc "racket-webview - A Web Based GUI library, based on a Qt WebEngine backend") (define scribblings '( - ("scrbl/web-racket.scrbl" () (gui-library) "web-racket") - ("scrbl/web-racket-version.scrbl" () (gui-library) "web-racket-version") - ("scrbl/web-wire.scrbl" () (gui-library) "web-wire") - ("scrbl/webui-wire-download.scrbl" () (gui-library) "webui-wire-download") - ("scrbl/webui-wire-ipc.scrbl" () (gui-library) "webui-wire-ipc") + ("scrbl/racket-webview-qt.scrbl" () (gui-library) "racket-webview-qt") + ("scrbl/racket-webview.scrbl" () (gui-library) "racket-webview") + ("scrbl/wv-context.scrbl" () (gui-library) "wv-context") + ("scrbl/wv-element.scrbl" () (gui-library) "wv-element") + ("scrbl/wv-input.scrbl" () (gui-library) "wv-input") + ("scrbl/wv-settings.scrbl" () (gui-library) "wv-settings") + ("scrbl/wv-window.scrbl" () (gui-library) "wv-window") + ("scrbl/rgba.scrbl" () (gui-library) "rgba") + "scrbl/rktwebview-api.scrbl" + "scrbl/rktwebviewqt-internals.scrbl" ) ) @@ -36,3 +41,4 @@ "scribble-lib" "net-doc" )) + diff --git a/js/boilerplate.css b/js/boilerplate.css new file mode 100644 index 0000000..a326381 --- /dev/null +++ b/js/boilerplate.css @@ -0,0 +1,3 @@ +body { + font-family: sans-serif; +} diff --git a/js/boilerplate.js b/js/boilerplate.js index bc4124b..5b0e7f5 100644 --- a/js/boilerplate.js +++ b/js/boilerplate.js @@ -2,7 +2,11 @@ if (window.rkt_event_queue === undefined) { window.rkt_event_queue = []; } window.rkt_put_evt = function(evt) { + evt.timestamp = Date.now(); window.rkt_event_queue.push(evt); + if (window.rkt_evt_frame_el) { + window.rkt_evt_frame_win.print(); + } }; window.rkt_event_info = function(e, id, evt) { diff --git a/js/menu.css b/js/menu.css new file mode 100644 index 0000000..2f56524 --- /dev/null +++ b/js/menu.css @@ -0,0 +1,113 @@ +div.menubar { + display: flex; + align-items: center; + width: 100%; + top: 0; + left: 0; + height: 2em; + background: #e0e0e0; + border-bottom: 1px solid black; + margin-bottom: 2px; +} + +div.menubar-item { + display: inline-block; + height: 100%; + align-content: center; + padding-left: 0.5em; + padding-right: 0.5em; + cursor: default; +} + +div.menu, div.submenu { + display: flex; + flex-direction: column; + background: #e0e0e0; + border: 1px solid black; + z-index: 9999; + margin-top: 0.4em; + margin-left: -0.5em; + position: absolute; +} + +div.submenu { + position: absolute; + left: calc(100% + 1em); + top: 1em; +} + +div.menu-item { + min-width: 150px; + height: 2em; + padding-left: 0.5em; + align-content: center; + align-items: center; + display: flex; + cursor: default; +} + +div.menu-item span.menu-icon { + width: 2em; + height: 2em; + padding: 0; + margin: 0; + display: flex; + padding-left: 3px; +} + +div.menu-item span.menu-name { + padding-left: 0.25em; + display: inline-block; + padding-right: 0.5em; +} + +div.menu-item span.menu-submenu { + float: right; +} + +span.menu-icon img { + width: 85%; + height: 85%; + align-self: center; +} + +div.menu-item.separator { + border-top: 1px solid black; +} + +div.menubar-item:hover, div.menu-item:hover { + background: #c0c0c0;; +} + +.popup-menu, .popup-submenu { + display: flex; + flex-direction: column; + margin: 5px; + padding: 5px; + position: absolute; + z-index: 9999; + border: 1px solid black; + background: #e0e0e0; + color: black; +} + +.popup-submenu { + display: none; +} + +.menubar .menu-item span.menu-icon, .popup-menu .menu-item span.menu-icon { + min-width: unset; + width: unset; +} + +.menubar .menu-item { + min-width: unset; + width: unset; + color: black; +} + +.menu-item span.menu-name { + text-wrap: nowrap; +} + + diff --git a/js/menu.js b/js/menu.js new file mode 100644 index 0000000..12521b0 --- /dev/null +++ b/js/menu.js @@ -0,0 +1,132 @@ + + +window._web_wire_popup_menu = function(menu, x = -1, y = -1, kind = 'popup') { + if (menu.id == '#f') { menu.id = null; } + let menu_id = (kind == 'popup') ? '@@popup-menu@@' : '@@menubar@@'; + let submenu_els = []; + let triggerMenuItem; + let clearPopupMenu = function() { + if (kind == 'popup') { + let el = document.getElementById(menu_id); + if (el !== null) { + el.innerHTML = ''; + el.style.display = 'none'; + } + if (menu.id !== null) { + // Delay this trigger, because one could have choosen a menu item and we want this + // to be triggered before the clear command is send. + // But if no menu item has been selected, the clear command should + // eventually be send. + setTimeout(function () { + console.log("Sending clear trigger for menu clearance : " + menu.id); + let obj = { evt: 'menu-item-choosen', id: menu.id, menu_item: menu.id }; + window.rkt_put_evt(obj); + }, 250); + } + } else { + // hide all submenus + submenu_els.forEach(function (el) { el.style.display = 'none'; }); + } + }; + triggerMenuItem = function(id) { + console.log("Triggering menu item : " + id); + let obj = { evt: 'menu-item-choosen', id: id, menu_item: id }; + window.rkt_put_evt(obj); + }; + let showSubMenu = function(menu_el, item_el, el, parent_type) { + if (parent_type == 'menu') { + el.style.display = 'flex'; + let rect = item_el.getBoundingClientRect(); + let r = rect.left; + let t = rect.height; + el.style.left = r + 'px'; + el.style.top = t + 'px'; + } else { + el.style.display = "flex"; + let rect = menu_el.getBoundingClientRect(); + let irect =item_el.getBoundingClientRect(); + let r = rect.width + 5; + let t = irect.y - rect.y; + el.style.left = r + "px"; + el.style.top = t + "px"; + } + }; + let hideSubMenu = function(el) { el.style.display = "none"; }; + let makePopupMenu = function(el, menu, visible, type) { + let i; + let N = menu.length; + for(i = 0; i < N; i++) { + let item = menu[i]; + let item_el = document.createElement("div"); + item_el.id = item.id; + item_el.classList.add("menu-item"); + let item_el_icon = document.createElement('span'); + item_el_icon.classList.add("menu-icon"); + if (item.icon) { + let icon_img = document.createElement('img'); + icon_img.setAttribute('src', item.icon); + item_el_icon.appendChild(icon_img); + } + if (item.separator) { + item_el.classList.add("separator"); + } + let item_el_name = document.createElement('span'); + item_el_name.classList.add('menu-name'); + item_el_name.innerHTML = item.name; + let item_el_submenu = document.createElement('span'); + item_el_submenu.classList.add('menu-submenu'); + if (item.submenu) { + if (type == 'submenu' || kind == 'popup') { + item_el_submenu.innerHTML = '>'; + } + item_el.setAttribute('type', 'submenu'); + let submenu_el = document.createElement("div"); + submenu_els.push(submenu_el); + submenu_el.classList.add("submenu"); + submenu_el.classList.add("menu"); + item_el.appendChild(submenu_el); + submenu_el.style.display = 'none'; + makePopupMenu(submenu_el, item.submenu.menu, false, 'submenu'); + item_el.addEventListener('mouseenter', function () { showSubMenu(el, item_el, submenu_el, type); }); + item_el.addEventListener('mouseleave', function () { hideSubMenu(submenu_el); }); + } else { + item_el.setAttribute('type', 'item'); + item_el.addEventListener('click', function() { triggerMenuItem(item.id); }); + } + item_el.appendChild(item_el_icon); + item_el.appendChild(item_el_name); + item_el.appendChild(item_el_submenu); + el.appendChild(item_el); + } + }; + let el = document.getElementById(menu_id); + if (el === null) { + el = document.createElement("div"); + el.id = menu_id; + el.classList.add((kind == 'popup') ? "popup-menu" : "menubar"); + if (kind == 'popup') { + el.classList.add("menu"); + document.body.appendChild(el); + } else { + document.body.prepend(el); + } + } else { + el.innerHTML = ''; + } + makePopupMenu(el, menu.menu, true, 'menu'); + el.style.left = x + "px"; + el.style.top = y + "px"; + el.style.display = "flex"; + let clearer_f = function() { + clearPopupMenu(); + document.body.removeEventListener('click', clearer_f); + document.body.removeEventListener('contextmenu', clearer_f); + }; + document.body.addEventListener('click', clearer_f); + document.body.addEventListener('contextmenu', clearer_f); +}; + +window._web_wire_menu = function(_menubar) { + let menubar = JSON.parse(_menubar); + window._web_wire_popup_menu(menubar, -1, -1, 'menubar'); +}; diff --git a/main.rkt b/main.rkt index 97d324f..bb44d12 100644 --- a/main.rkt +++ b/main.rkt @@ -6,12 +6,18 @@ (require "private/wv-dialog.rkt") (require "private/wv-element.rkt") (require "private/wv-input.rkt") +(require "private/rgba.rkt") +(require "private/mimetypes.rkt") +(require "private/menu.rkt") (provide (all-from-out "private/wv-context.rkt" "private/wv-window.rkt" "private/wv-dialog.rkt" "private/wv-element.rkt" "private/wv-input.rkt" + "private/rgba.rkt" + "private/mimetypes.rkt" + "private/menu.rkt" ) webview-set-loglevel webview-version diff --git a/private/lib/linux/x86_64/librktwebview.so b/private/lib/linux/x86_64/librktwebview.so index 8a3dc76..68053b3 100755 Binary files a/private/lib/linux/x86_64/librktwebview.so and b/private/lib/linux/x86_64/librktwebview.so differ diff --git a/private/lib/linux/x86_64/rktwebview_prg b/private/lib/linux/x86_64/rktwebview_prg index b8db3e4..53c74f5 100755 Binary files a/private/lib/linux/x86_64/rktwebview_prg and b/private/lib/linux/x86_64/rktwebview_prg differ diff --git a/private/menu.rkt b/private/menu.rkt index f36f55f..f3170d6 100644 --- a/private/menu.rkt +++ b/private/menu.rkt @@ -1,60 +1,72 @@ (module menu racket/base - (require json) + (require json + net/url) - (provide menu - menu-item - is-menu? - menu-set-callback! - menu-set-icon! - menu-set-title! - menu->json - with-menu-item - menu-for-each - ww-menu-item-callback - ww-menu-item-id - ww-menu-id + (provide wv-menu + wv-menu-item + is-wv-menu? + wv-menu-set-callback! + wv-menu-set-icon! + wv-menu-set-title! + wv-menu->json + with-wv-menu-item + wv-menu-for-each + wv-menu-item-callback + wv-menu-item-id + wv-menu-id ) - (define-struct ww-menu-item - (id [title #:mutable] [icon-file #:mutable] [callback #:mutable] [submenu #:mutable] [separator #:mutable]) + + (define-struct ww-menu-item* + (id [title #:mutable] [icon-url #:mutable] [callback #:mutable] [submenu #:mutable] [separator #:mutable]) #:transparent) - (define-struct ww-menu + (define-struct ww-menu* (id [items #:mutable]) #:transparent ) - (define (is-menu? mnu) - (if (ww-menu? mnu) - (if (list? (ww-menu-items mnu)) + + (define (wv-menu-item-callback mi) + (ww-menu-item*-callback mi)) + + (define (wv-menu-item-id mi) + (ww-menu-item*-id mi)) + + (define (wv-menu-id m) + (ww-menu*-id m)) + + (define (is-wv-menu? mnu) + (if (ww-menu*? mnu) + (if (list? (ww-menu*-items mnu)) (letrec ((f (lambda (m) (if (null? m) #t - (if (ww-menu-item? (car m)) - (if (eq? (ww-menu-item-submenu (car m)) #f) + (if (ww-menu-item*? (car m)) + (if (eq? (ww-menu-item*-submenu (car m)) #f) (f (cdr m)) - (and (is-menu? (ww-menu-item-submenu (car m))) + (and (is-wv-menu? (ww-menu-item*-submenu (car m))) (f (cdr m)))) #f) )) )) - (f (ww-menu-items mnu))) + (f (ww-menu*-items mnu))) #f) #f)) - (define (menu . items) + (define (wv-menu . items) (let ((menu-id #f)) (when (symbol? (car items)) (set! menu-id (car items)) (set! items (cdr items))) (when (list? (car items)) (set! items (car items))) - (make-ww-menu menu-id items))) + (make-ww-menu* menu-id items))) - (define (menu-item id title - #:icon-file [icon-file #f] + (define (wv-menu-item id title + #:icon-url [icon-url #f] #:callback [callback (lambda args #t)] #:submenu [submenu #f] #:separator [separator #f]) @@ -62,47 +74,49 @@ (error "menu-item needs an id of symbol?")) (unless (string? title) (error "menu-item needs a title of string?")) - (unless (or (eq? icon-file #f) (string? icon-file) (path? icon-file)) + (unless (or (eq? icon-url #f) (string? icon-url) (url? icon-url)) (error "menu-item's optional argument icon-file must be #f, string? or path?")) - (unless (or (eq? submenu #f) (is-menu? submenu)) + (unless (or (eq? submenu #f) (is-wv-menu? submenu)) (error "menu-item's optional argument submenu must be #f or is-menu?")) (unless (boolean? separator) (error "menu-item's optional argument separator must be boolean?")) - (make-ww-menu-item id title icon-file callback submenu separator)) + (let ((u (if (url? icon-url) (url->string icon-url) icon-url))) + (make-ww-menu-item* id title u callback submenu separator)) + ) - (define (menu->hash menu . for-json) + (define (wv-menu->hash menu . for-json) (let ((fj (if (null? for-json) #f (car for-json)))) - (unless (is-menu? menu) + (unless (is-wv-menu? menu) (error "menu->hash must be called with a menu")) - (let* ((items (ww-menu-items menu)) + (let* ((items (ww-menu*-items menu)) (r (map (λ (item) (let ((h (make-hasheq))) - (hash-set! h 'id (format "~a" (ww-menu-item-id item))) - (hash-set! h 'name (ww-menu-item-title item)) - (unless (eq? (ww-menu-item-icon-file item) #f) - (hash-set! h 'icon (ww-menu-item-icon-file item))) - (unless (eq? (ww-menu-item-submenu item) #f) - (hash-set! h 'submenu (menu->hash (ww-menu-item-submenu item) fj))) - (unless (eq? (ww-menu-item-separator item) #f) + (hash-set! h 'id (format "~a" (ww-menu-item*-id item))) + (hash-set! h 'name (ww-menu-item*-title item)) + (unless (eq? (ww-menu-item*-icon-url item) #f) + (hash-set! h 'icon (ww-menu-item*-icon-url item))) + (unless (eq? (ww-menu-item*-submenu item) #f) + (hash-set! h 'submenu (wv-menu->hash (ww-menu-item*-submenu item) fj))) + (unless (eq? (ww-menu-item*-separator item) #f) (hash-set! h 'separator #t)) h )) items)) ) (let ((h (make-hasheq))) (hash-set! h 'menu r) - (hash-set! h 'id (if fj (format "~a" (ww-menu-id menu)) (ww-menu-id menu))) + (hash-set! h 'id (if fj (format "~a" (ww-menu*-id menu)) (ww-menu*-id menu))) h)))) - (define (menu-for-each menu cb) - (let ((items (ww-menu-items menu))) + (define (wv-menu-for-each menu cb) + (let ((items (ww-menu*-items menu))) (letrec ((f (λ (items) (if (null? items) #t (let ((item (car items))) - (let ((submenu (ww-menu-item-submenu item))) + (let ((submenu (ww-menu-item*-submenu item))) (if (eq? submenu #f) (cb item) - (menu-for-each submenu cb))) + (wv-menu-for-each submenu cb))) (f (cdr items)) ) ) @@ -110,23 +124,23 @@ )) (f items)))) - (define (menu->json menu) + (define (wv-menu->json menu) (let ((o (open-output-string))) - (write-json (menu->hash menu #t) o) + (write-json (wv-menu->hash menu #t) o) (get-output-string o))) - (define (find-menu-item menu id) - (let ((items (ww-menu-items menu))) + (define (find-wv-menu-item menu id) + (let ((items (ww-menu*-items menu))) (letrec ((f (λ (items) (if (null? items) #f (let ((item (car items))) - (if (eq? (ww-menu-item-id item) id) + (if (eq? (ww-menu-item*-id item) id) item - (let ((submenu (ww-menu-item-submenu item))) + (let ((submenu (ww-menu-item*-submenu item))) (if (eq? submenu #f) (f (cdr items)) - (let ((found-item (find-menu-item submenu id))) + (let ((found-item (find-wv-menu-item submenu id))) (if (eq? found-item #f) (f (cdr items)) found-item)) @@ -136,37 +150,38 @@ )) (f items)))) - (define (with-menu-item menu id cb) - (unless (is-menu? menu) + (define (with-wv-menu-item menu id cb) + (unless (is-wv-menu? menu) (error "menu must be of is-menu?")) (unless (symbol? id) (error "id must be of symbol?")) - (let ((item (find-menu-item menu id))) + (let ((item (find-wv-menu-item menu id))) (if (eq? item #f) (error (format "cannot find id'~a in given menu" id)) (cb item))) menu) - (define (menu-set-title! menu id title) + (define (wv-menu-set-title! menu id title) (unless (string? title) (error "title must be of string?")) - (with-menu-item menu id + (with-wv-menu-item menu id (λ (item) - (set-ww-menu-item-title! item title)))) + (set-ww-menu-item*-title! item title)))) - (define (menu-set-icon! menu id icon) - (unless (or (eq? icon #f) (path? icon) (string? icon)) + (define (wv-menu-set-icon! menu id icon-url) + (unless (or (eq? icon-url #f) (url? icon-url) (string? icon-url)) (error "title must be of #f, string? or path?")) - (with-menu-item menu id + (with-wv-menu-item menu id (λ (item) - (set-ww-menu-item-icon-file! item icon)))) + (let ((u (if (url? icon-url) (url->string icon-url) icon-url))) + (set-ww-menu-item*-icon-url! item u))))) - (define (menu-set-callback! menu id cb) + (define (wv-menu-set-callback! menu id cb) (unless (procedure? cb) (error "callback must be of procedure?")) - (with-menu-item menu id + (with-wv-menu-item menu id (λ (item) - (set-ww-menu-item-callback! item cb)))) + (set-ww-menu-item*-callback! item cb)))) ); end of module diff --git a/private/racket-webview-qt.rkt b/private/racket-webview-qt.rkt index b8a6460..3fa84f7 100644 --- a/private/racket-webview-qt.rkt +++ b/private/racket-webview-qt.rkt @@ -590,7 +590,7 @@ ; ))))) (let ((handle (make-rkt-wv wv evt-queue evt-callback #t close-callback))) (thread (λ () - (sleep 1) + (sleep 0.01) (letrec ((f (λ () (let ((r (rkt-process-events handle))) (if (eq? r 'quit) diff --git a/private/racket-webview-version.rkt b/private/racket-webview-version.rkt index adee044..9ded978 100644 --- a/private/racket-webview-version.rkt +++ b/private/racket-webview-version.rkt @@ -7,5 +7,5 @@ (define webview-major 0) (define webview-minor 1) -(define webview-patch 0) +(define webview-patch 1) diff --git a/private/racket-webview.rkt b/private/racket-webview.rkt index f797406..0e4b7e7 100644 --- a/private/racket-webview.rkt +++ b/private/racket-webview.rkt @@ -5,6 +5,7 @@ "utils.rkt" "mimetypes.rkt" "rgba.rkt" + "menu.rkt" finalizer racket/async-channel web-server/http @@ -73,6 +74,8 @@ webview-set-html! webview-base-url + webview-set-menu! + webview-set-innerHTML! webview-set-value! @@ -105,6 +108,7 @@ webview-standard-file-getter webview-default-boilerplate-js + webview-default-boilerplate-css webview-version webview-info @@ -123,16 +127,38 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define-runtime-path js-path "../js") +(define-runtime-path css-path "../js") (define (webview-default-boilerplate-js . custom-js) - (let ((file (build-path js-path "boilerplate.js"))) - (let ((bjs (file->string file))) + (let ((file (build-path js-path "boilerplate.js")) + (menu-js-file (build-path js-path "menu.js"))) + (let ((bjs (file->string file)) + (mjs (file->string menu-js-file)) + ) (let ((js (string-append bjs + mjs (if (null? custom-js) "" ((car custom-js)))))) js)))) +(define (webview-default-boilerplate-css . custom-css) + (let ((file (build-path css-path "boilerplate.css")) + (menu-css-file (build-path css-path "menu.css"))) + (let ((bcss (file->string file)) + (mcss (file->string menu-css-file)) + ) + (let ((css (string-append bcss + mcss + (if (null? custom-css) + "" + ((car custom-css))) + ) + ) + ) + css)))) + + (define-struct wv-context ([context #:mutable] [port #:mutable] @@ -142,6 +168,7 @@ [request-count #:mutable] [sec-token-cache #:mutable] [cert-ou-token #:mutable] + [boilerplate-css #:mutable] ) #:transparent ) @@ -153,16 +180,16 @@ ) #:transparent) +(define re_head #px"[<][/][Hh][eE][aA][dD][>]") + (define (process-html context path out) (let ((html (file->string path))) - (display html out))) -; (boilerplate-js ((wv-context-boilerplate-js wv-win-handle)))) -; (set! html (string-replace html "
" -; (string-append "" "\n" -; "" "\n"))) -; (display html out))) + (let ((html* (regexp-replace re_head html + (string-append "\n" + "")))) + (display html* out)))) (define (process-file context ext path out) (let ((content (file->bytes path))) @@ -414,11 +441,13 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define/contract (webview-new-context file-getter - #:boilerplate-js [bj (webview-default-boilerplate-js)]) - (->* (procedure?) (#:boilerplate-js string?) wv-context?) + #:boilerplate-js [bj (webview-default-boilerplate-js)] + #:boilerplate-css [bc (webview-default-boilerplate-css)]) + (->* (procedure?) (#:boilerplate-js string? #:boilerplate-css string?) wv-context?) (let* ((h (make-wv-context 0 0 file-getter #f #f 0 (make-lru 250 #:cmp eq?) (symbol->string (make-security-token)) + bc )) (cert (generate-self-signed-cert 2048 365 '("127.0.0.1" "localhost") "NL" "Dijkema" @@ -497,6 +526,17 @@ ) ) +(define/contract (webview-set-menu! wv menu) + (-> wv-win? is-wv-menu? symbol?) + (let* ((json (wv-menu->json menu)) + (js (string-append "window._web_wire_menu('" + json + "');")) + ) + (webview-run-js wv js) + ) + ) + (define (loglevel? x) (and (symbol? x) (or (eq? x 'error) (eq? x 'info) (eq? x 'debug) (eq? x 'warning)))) diff --git a/private/wv-context.rkt b/private/wv-context.rkt index 47c4f29..b98d11b 100644 --- a/private/wv-context.rkt +++ b/private/wv-context.rkt @@ -13,7 +13,9 @@ base-path [file-getter (webview-standard-file-getter base-path)] [context-js (λ () "")] + [context-css (λ () "")] [boilerplate-js (webview-default-boilerplate-js context-js)] + [boilerplate-css (webview-default-boilerplate-css context-css)] [ini (error "You need to provide a 'ini' file settings interface for settings, e.g. simple-ini/class")] ) @@ -35,7 +37,8 @@ (begin (set! wv-context (webview-new-context file-getter - #:boilerplate-js boilerplate-js)) + #:boilerplate-js boilerplate-js + #:boilerplate-css boilerplate-css)) (set! settings-obj (new wv-settings% [ini ini] [wv-context 'global])) ) ) diff --git a/private/wv-dialog.rkt b/private/wv-dialog.rkt index fde2f6b..33ce322 100644 --- a/private/wv-dialog.rkt +++ b/private/wv-dialog.rkt @@ -38,9 +38,9 @@ (let ((x (inexact->exact (round (exact->inexact (+ px xx))))) (y (inexact->exact (round (exact->inexact (+ py yy))))) ) - (displayln "move") + (displayln (format "move ~a ~a" x y)) (send this move x y) - (displayln "resize") + (displayln (format "resize ~a ~a" x y)) (send this resize dw dh) ) ) diff --git a/private/wv-window.rkt b/private/wv-window.rkt index 77cf0e9..726b841 100644 --- a/private/wv-window.rkt +++ b/private/wv-window.rkt @@ -145,6 +145,7 @@ (define (event-handler wv evt) (let ((event (hash-ref evt 'event 'unknown-event)) ) + (displayln evt) (cond ((eq? event 'resize) (send this resized (hash-ref evt 'w) (hash-ref evt 'h))) @@ -163,7 +164,7 @@ (let* ((je (hash-copy (hash-ref evt 'js-evt))) (e (make-hash))) (hash-set! e 'evt (string->symbol (hash-ref je 'evt))) - (hash-set! e 'id (string->symbol (hash-ref je 'id #f))) + (hash-set! e 'id (string->symbol (hash-ref je 'id "nil"))) (hash-set! e 'data (hash-ref je 'js_evt (make-hash))) (hash-set! e 'event 'js-evt) (when (eq? (send this js-event e) 'wv-unhandled-js-event) @@ -244,7 +245,6 @@ ) ) ) - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Commands @@ -257,6 +257,15 @@ (define/public (remove-class! selector-or-id cl) (webview-remove-class! wv selector-or-id cl) this) + + (define/public (set-menu! menu) + (webview-set-menu! wv menu) + this) + + (define/public (connect-menu! id callback) + (send this bind! (string->symbol (format "~a" id)) 'menu-item-choosen + (λ (el evt data) + (callback)))) (define/public (devtools) (webview-devtools wv) diff --git a/rktwebview_qt/rktutils.cpp b/rktwebview_qt/rktutils.cpp index 4ee17f6..7bf54e1 100644 --- a/rktwebview_qt/rktutils.cpp +++ b/rktwebview_qt/rktutils.cpp @@ -27,3 +27,4 @@ QHash