Add initial User Interface code
This commit is contained in:
7
OSN.asd
7
OSN.asd
@ -35,10 +35,15 @@
|
|||||||
(:module "src"
|
(:module "src"
|
||||||
:components
|
:components
|
||||||
((:file "pkgdef")
|
((:file "pkgdef")
|
||||||
|
(:file "globals" :depends-on ("pkgdef"))
|
||||||
(:file "conditions" :depends-on ("pkgdef"))
|
(:file "conditions" :depends-on ("pkgdef"))
|
||||||
(:file "osn" :depends-on ("pkgdef"))
|
(:file "osn" :depends-on ("pkgdef"))
|
||||||
(:file "osn-parser" :depends-on ("pkgdef" "conditions" "osn"))
|
(:file "osn-parser" :depends-on ("pkgdef" "conditions" "osn"))
|
||||||
(:file "osn-writer" :depends-on ("pkgdef" "conditions" "osn"))
|
(:file "osn-writer" :depends-on ("pkgdef" "conditions" "osn"))
|
||||||
(:file "osn-to-os10" :depends-on ("pkgdef" "conditions" "osn")))
|
(:file "osn-to-os10" :depends-on ("pkgdef" "conditions" "osn"))
|
||||||
|
(:file "ui-utils" :depends-on ("pkgdef" "globals" "conditions"))
|
||||||
|
(:file "debugger-ui" :depends-on ("pkgdef" "globals" "conditions" "ui-utils"))
|
||||||
|
(:file "osn-viewer" :depends-on ("pkgdef" "globals" "conditions" "osn" "osn-parser" "osn-writer" "osn-to-os10" "ui-utils"))
|
||||||
|
(:file "win-ui" :depends-on ("pkgdef" "globals" "conditions" "ui-utils" "debugger-ui" "osn-viewer")))
|
||||||
:depends-on ("lib")))
|
:depends-on ("lib")))
|
||||||
:depends-on ("cl-ppcre" "yacc" "cxml"))
|
:depends-on ("cl-ppcre" "yacc" "cxml"))
|
||||||
|
|||||||
141
src/debugger-ui.lisp
Normal file
141
src/debugger-ui.lisp
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
;;;; OpenScenarioNext --- OpenScenario Language Design
|
||||||
|
;;;; This is copyrighted software. See documentation for terms.
|
||||||
|
;;;;
|
||||||
|
;;;; debugger-ui.lisp --- Debugger User Interface
|
||||||
|
|
||||||
|
(cl:in-package #:openscenarionext-bench)
|
||||||
|
|
||||||
|
;;;; %File Description:
|
||||||
|
;;;;
|
||||||
|
;;;; Contains the user interface code for the debugger.
|
||||||
|
;;;;
|
||||||
|
|
||||||
|
(defun find-ob-abort-restart (restarts)
|
||||||
|
(find-if (lambda (restart)
|
||||||
|
(and (eql (restart-name restart) 'abort)
|
||||||
|
(string= (princ-to-string restart) "Return to event loop.")))
|
||||||
|
restarts))
|
||||||
|
|
||||||
|
(capi:define-interface simple-debugger-interface ()
|
||||||
|
((message-text :initarg :message-text :initform nil :reader simple-debugger-interface-message-text)
|
||||||
|
(condition :initarg :condition :reader simple-debugger-interface-condition)
|
||||||
|
(restarts :initarg :restarts :initform nil :reader simple-debugger-interface-restarts)
|
||||||
|
(cancel-text :initarg :cancel-text :initform "Exit OSN Bench"
|
||||||
|
:reader simple-debugger-interface-cancel-text))
|
||||||
|
(:panes
|
||||||
|
(message-text-pane
|
||||||
|
capi:display-pane
|
||||||
|
:text (if message-text (capi:wrap-text message-text 100) "")
|
||||||
|
:internal-max-width '(:character 100))
|
||||||
|
(condition-text-pane
|
||||||
|
capi:display-pane
|
||||||
|
:text (capi:wrap-text (princ-to-string condition) 100)
|
||||||
|
:internal-max-width '(:character 100))
|
||||||
|
(restart-list
|
||||||
|
capi:list-panel
|
||||||
|
:title "Possible ways to continue:"
|
||||||
|
:items restarts
|
||||||
|
:interaction :single-selection
|
||||||
|
:selection nil
|
||||||
|
:visible-min-height '(:character 5)
|
||||||
|
:callback-type :none
|
||||||
|
:selection-callback
|
||||||
|
(lambda ()
|
||||||
|
(if (capi:choice-selected-items restart-list)
|
||||||
|
(capi:set-button-panel-enabled-items button-panel :enable '("Continue"))
|
||||||
|
(capi:set-button-panel-enabled-items button-panel :disable '("Continue"))))
|
||||||
|
:action-callback
|
||||||
|
(lambda ()
|
||||||
|
(when (capi:choice-selected-items restart-list)
|
||||||
|
(capi:exit-dialog (capi:choice-selected-item restart-list)))))
|
||||||
|
(button-panel
|
||||||
|
capi:push-button-panel
|
||||||
|
:items `(,@(when restarts (list "Continue"))
|
||||||
|
,@(when (find-ob-abort-restart restarts) (list "Abort"))
|
||||||
|
,@(when *ob-developer-edition*
|
||||||
|
(list "Debug"))
|
||||||
|
,cancel-text)
|
||||||
|
:callback-type :none
|
||||||
|
:callbacks
|
||||||
|
(nconc
|
||||||
|
(when restarts
|
||||||
|
(list (lambda ()
|
||||||
|
(capi:exit-dialog (capi:choice-selected-item restart-list)))))
|
||||||
|
(let ((abort-restart (find-ob-abort-restart restarts)))
|
||||||
|
(when abort-restart
|
||||||
|
(list (lambda ()
|
||||||
|
(capi:exit-dialog abort-restart)))))
|
||||||
|
(when *ob-developer-edition*
|
||||||
|
(list (lambda () (capi:exit-dialog condition))))
|
||||||
|
(list #'capi:abort-dialog))))
|
||||||
|
(:layouts
|
||||||
|
(main-layout
|
||||||
|
capi:column-layout
|
||||||
|
'(contents-layout button-panel)
|
||||||
|
:gap 12
|
||||||
|
:adjust :right)
|
||||||
|
(contents-layout
|
||||||
|
capi:column-layout
|
||||||
|
(nconc
|
||||||
|
(when message-text (list 'message-text-pane))
|
||||||
|
(list 'condition-text-pane)
|
||||||
|
(when restarts (list 'restart-list)))
|
||||||
|
:gap 12))
|
||||||
|
(:default-initargs
|
||||||
|
:layout 'main-layout))
|
||||||
|
|
||||||
|
(defmethod initialize-instance :after ((instance simple-debugger-interface) &key)
|
||||||
|
(capi:set-button-panel-enabled-items (slot-value instance 'button-panel)
|
||||||
|
:disable '("Continue")))
|
||||||
|
|
||||||
|
(defun run-simple-debugger-interface (top-level-interface condition &rest initargs)
|
||||||
|
(let ((result
|
||||||
|
(capi:display-dialog
|
||||||
|
(apply #'make-instance 'simple-debugger-interface
|
||||||
|
:condition condition
|
||||||
|
initargs))))
|
||||||
|
(typecase result
|
||||||
|
(null
|
||||||
|
;; Exit
|
||||||
|
(capi:quit-interface top-level-interface)
|
||||||
|
;; Sleep to prevent default condition handling
|
||||||
|
(sleep 120)
|
||||||
|
;; Force quit if we hang long enough
|
||||||
|
(lw:quit :status 1 :ignore-errors-p t))
|
||||||
|
(condition (invoke-debugger result))
|
||||||
|
(t (invoke-restart result)))))
|
||||||
|
|
||||||
|
(defun select-restarts (condition &rest names)
|
||||||
|
(loop for restart-name in names
|
||||||
|
when (find-restart restart-name condition) collect it))
|
||||||
|
|
||||||
|
(defgeneric default-condition-handler (condition top-level-interface)
|
||||||
|
(:documentation "Default fallback handler."))
|
||||||
|
|
||||||
|
(defmethod default-condition-handler (condition top-level-interface)
|
||||||
|
nil)
|
||||||
|
|
||||||
|
(defmethod default-condition-handler ((condition error) top-level-interface)
|
||||||
|
(run-simple-debugger-interface
|
||||||
|
top-level-interface condition
|
||||||
|
:title "Internal OSN Bench Error"
|
||||||
|
:message-text
|
||||||
|
(format nil "Please contact the OSN Bench team at <~A> for ~
|
||||||
|
assistance, quoting the following piece of information:"
|
||||||
|
"info@pmsf.eu")
|
||||||
|
:restarts
|
||||||
|
(select-restarts condition 'continue 'ignore 'abort)))
|
||||||
|
|
||||||
|
(defmethod default-condition-handler ((condition osn-warning) top-level-interface)
|
||||||
|
(capi:display-dialog
|
||||||
|
(make-instance 'simple-debugger-interface
|
||||||
|
:condition condition
|
||||||
|
:title "OSN Bench Warning"
|
||||||
|
:cancel-text "OK")))
|
||||||
|
|
||||||
|
(defmethod default-condition-handler ((condition osn-error) top-level-interface)
|
||||||
|
(run-simple-debugger-interface
|
||||||
|
top-level-interface condition
|
||||||
|
:title "Serious OSN Bench Error"
|
||||||
|
:restarts
|
||||||
|
(select-restarts condition 'continue 'ignore 'abort)))
|
||||||
14
src/globals.lisp
Normal file
14
src/globals.lisp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
;;;; OpenScenarioNext --- OpenScenario Language Design
|
||||||
|
;;;; This is copyrighted software. See documentation for terms.
|
||||||
|
;;;;
|
||||||
|
;;;; globals.lisp --- Global information
|
||||||
|
|
||||||
|
(cl:in-package #:openscenarionext-bench)
|
||||||
|
|
||||||
|
;;;; %File Description:
|
||||||
|
;;;;
|
||||||
|
;;;; Global variable and constant definitions
|
||||||
|
;;;;
|
||||||
|
|
||||||
|
(defparameter *ob-developer-edition* t
|
||||||
|
"Indicates whether we are running in the developer environment or not.")
|
||||||
198
src/osn-viewer.lisp
Normal file
198
src/osn-viewer.lisp
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
;;;; OpenScenarioNext --- OpenScenario Language Design
|
||||||
|
;;;; This is copyrighted software. See documentation for terms.
|
||||||
|
;;;;
|
||||||
|
;;;; osn-viewer.lisp --- Generic OSN Viewer User Interface
|
||||||
|
|
||||||
|
(cl:in-package #:openscenarionext-bench)
|
||||||
|
|
||||||
|
;;;; %File Description:
|
||||||
|
;;;;
|
||||||
|
;;;; OSN Viewer/Editor
|
||||||
|
;;;;
|
||||||
|
|
||||||
|
(defun application-interface-new-osn (interface)
|
||||||
|
(capi:display
|
||||||
|
(make-instance 'osn-viewer
|
||||||
|
:source nil
|
||||||
|
:osn-buffer
|
||||||
|
(editor:make-buffer "Unknown" :temporary t))
|
||||||
|
:screen
|
||||||
|
(derive-main-interface-screen interface)))
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; OSN Viewer
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(defun osn-maybe-parse-buffer (buffer)
|
||||||
|
(editor:with-buffer-locked (buffer :for-modification nil)
|
||||||
|
(let ((string (editor:points-to-string
|
||||||
|
(editor:buffers-start buffer)
|
||||||
|
(editor:buffers-end buffer))))
|
||||||
|
(with-input-from-string (stream string)
|
||||||
|
(ignore-errors
|
||||||
|
(list (osn-io:parse-osn-stream stream)))))))
|
||||||
|
|
||||||
|
(capi:define-interface osn-viewer (document-interface)
|
||||||
|
((document-kind :initform "OSN Viewer")
|
||||||
|
(document-icon :initform "FMIBenchFMD.ico")
|
||||||
|
(osn-buffer :initarg :osn-buffer :initform nil
|
||||||
|
:accessor osn-viewer-osn-buffer))
|
||||||
|
(:panes
|
||||||
|
(osn-editor-pane
|
||||||
|
capi:editor-pane
|
||||||
|
:echo-area t
|
||||||
|
:change-callback
|
||||||
|
(lambda (pane point old-len new-len)
|
||||||
|
(setf (capi:graph-pane-roots osn-graph-pane)
|
||||||
|
(osn-maybe-parse-buffer
|
||||||
|
(capi:editor-pane-buffer pane))))
|
||||||
|
:buffer osn-buffer)
|
||||||
|
(osn-graph-pane
|
||||||
|
capi:graph-pane
|
||||||
|
:roots (osn-maybe-parse-buffer osn-buffer)
|
||||||
|
:print-function
|
||||||
|
(lambda (object)
|
||||||
|
(typecase object
|
||||||
|
(scenario (format nil "Scenario ~A"
|
||||||
|
(scenario-name object)))
|
||||||
|
(act (format nil "Act ~A" (act-name object)))
|
||||||
|
(rule (format nil "Rule @~A~@[ %~A~]"
|
||||||
|
(rule-condition object)
|
||||||
|
(rule-modifier object)))
|
||||||
|
(t (princ-to-string object))))
|
||||||
|
:children-function
|
||||||
|
(lambda (root)
|
||||||
|
(typecase root
|
||||||
|
(osn-file (list (osn-file-scenario root)))
|
||||||
|
(scenario
|
||||||
|
(append (scenario-acts root)
|
||||||
|
(scenario-prototypes root)
|
||||||
|
(scenario-resources root)))
|
||||||
|
(act (act-rules root))
|
||||||
|
(rule (rule-actions root))
|
||||||
|
(t nil)))))
|
||||||
|
(:layouts
|
||||||
|
(osn-editor-layout
|
||||||
|
capi:column-layout
|
||||||
|
'(osn-editor-pane))
|
||||||
|
(osn-graph-layout
|
||||||
|
capi:column-layout
|
||||||
|
'(osn-graph-pane))
|
||||||
|
(switchable-layout
|
||||||
|
capi:switchable-layout
|
||||||
|
'(osn-editor-layout osn-graph-layout))
|
||||||
|
(tab-layout
|
||||||
|
capi:tab-layout
|
||||||
|
'(switchable-layout)
|
||||||
|
:items (list
|
||||||
|
'("Editor" . osn-editor-layout)
|
||||||
|
'("Graph" . osn-graph-layout))
|
||||||
|
:print-function #'car
|
||||||
|
:callback-type :interface-data
|
||||||
|
:selection-callback
|
||||||
|
(lambda (interface item)
|
||||||
|
(let ((view (slot-value interface (cdr item))))
|
||||||
|
(setf (capi:switchable-layout-visible-child switchable-layout) view))))
|
||||||
|
(main-layout
|
||||||
|
capi:column-layout
|
||||||
|
'(tab-layout)))
|
||||||
|
(:menus
|
||||||
|
(file-menu
|
||||||
|
"File"
|
||||||
|
((:component
|
||||||
|
((:menu
|
||||||
|
(("OSN File"
|
||||||
|
:callback 'application-interface-new-osn
|
||||||
|
:callback-type :interface))
|
||||||
|
:title "New")
|
||||||
|
("Open ..."
|
||||||
|
:accelerator "accelerator-o"
|
||||||
|
:callback 'application-interface-open
|
||||||
|
:callback-type :interface)
|
||||||
|
("Close"
|
||||||
|
:accelerator "accelerator-w"
|
||||||
|
:callback 'capi:quit-interface
|
||||||
|
:callback-type :interface)))
|
||||||
|
(:component
|
||||||
|
(("Save"
|
||||||
|
:callback 'document-interface-save
|
||||||
|
:callback-type :interface
|
||||||
|
:enabled-function 'document-interface-save-p)
|
||||||
|
("Save As ..."
|
||||||
|
:callback 'document-interface-save-as
|
||||||
|
:callback-type :interface)))
|
||||||
|
(:component
|
||||||
|
(("Refresh From File"
|
||||||
|
:callback 'document-interface-refresh
|
||||||
|
:callback-type :interface
|
||||||
|
:enabled-function #'document-interface-source)))
|
||||||
|
(:component
|
||||||
|
(("Quit OSN Bench"
|
||||||
|
:accelerator "accelerator-q"
|
||||||
|
:callback 'quit-osn-bench
|
||||||
|
:callback-type :interface)))))
|
||||||
|
(osn-menu
|
||||||
|
"OpenScenarioNext"
|
||||||
|
(
|
||||||
|
#+(or)
|
||||||
|
(:component
|
||||||
|
(("Export Import Warnings to CSV ..."
|
||||||
|
:callback 'export-viewer-warnings-to-csv
|
||||||
|
:callback-type :interface
|
||||||
|
:enabled-function 'viewer-warnings)))
|
||||||
|
(:component
|
||||||
|
(("Export to XOSC ..."
|
||||||
|
:callback 'export-osn-to-xosc
|
||||||
|
:callback-type :interface
|
||||||
|
:enabled-function
|
||||||
|
(lambda (x)
|
||||||
|
(declare (ignore x))
|
||||||
|
(capi:graph-pane-roots osn-graph-pane))))))))
|
||||||
|
(:menu-bar file-menu osn-menu)
|
||||||
|
(:default-initargs
|
||||||
|
:layout 'main-layout
|
||||||
|
:best-width 900
|
||||||
|
:best-height 600))
|
||||||
|
|
||||||
|
(defmethod document-interface-title-details ((interface osn-viewer))
|
||||||
|
"")
|
||||||
|
|
||||||
|
(defmethod document-interface-save-as-dialog ((interface osn-viewer))
|
||||||
|
(capi:prompt-for-file "OSN File"
|
||||||
|
:pathname (document-interface-source interface)
|
||||||
|
:operation :save
|
||||||
|
:if-exists :prompt
|
||||||
|
:if-does-not-exist :ok
|
||||||
|
:filters '("OSN Files" "*.osn"
|
||||||
|
"All Files" "*.*")
|
||||||
|
:filter "*.osn"
|
||||||
|
:owner interface)
|
||||||
|
"osn")
|
||||||
|
|
||||||
|
(defmethod document-interface-save-internal ((interface osn-viewer) pathname)
|
||||||
|
#+(or)
|
||||||
|
(csv-io:write-csv-file (csv-viewer-csv interface) pathname))
|
||||||
|
|
||||||
|
(defmethod document-interface-refresh-reader ((interface osn-viewer) pathname)
|
||||||
|
#+(or)
|
||||||
|
(csv-io:read-csv-file pathname))
|
||||||
|
|
||||||
|
(defmethod document-interface-refresh-internal ((interface osn-viewer) entity warnings)
|
||||||
|
(declare (ignore warnings))
|
||||||
|
(untouch-document-interface interface))
|
||||||
|
|
||||||
|
(defmethod export-osn-to-xosc ((viewer osn-viewer))
|
||||||
|
(let ((osn (first (capi:graph-pane-roots (slot-value viewer 'osn-graph-pane)))))
|
||||||
|
(when osn
|
||||||
|
(multiple-value-bind (pathname ok)
|
||||||
|
(capi:prompt-for-file "Export OSN To XOSC"
|
||||||
|
:operation :save
|
||||||
|
:filters '("XOSC Files" "*.XOSC")
|
||||||
|
:filter "*.XOSC")
|
||||||
|
(when ok
|
||||||
|
(capi:with-busy-interface (viewer)
|
||||||
|
(with-open-file (stream pathname #+(or) (ensure-pathname-type pathname "xosc")
|
||||||
|
:external-format :utf-8
|
||||||
|
:element-type :default
|
||||||
|
:direction :output :if-exists :supersede)
|
||||||
|
(osn-os10:write-os10-stream osn stream))))))))
|
||||||
@ -86,3 +86,12 @@
|
|||||||
#:openscenarionext)
|
#:openscenarionext)
|
||||||
(:export
|
(:export
|
||||||
#:write-os10-stream))
|
#:write-os10-stream))
|
||||||
|
|
||||||
|
(defpackage #:openscenarionext-bench
|
||||||
|
(:nicknames #:osn-bench #:ob)
|
||||||
|
(:use #:common-lisp
|
||||||
|
#:openscenarionext-utils
|
||||||
|
#:openscenarionext)
|
||||||
|
(:export
|
||||||
|
#:start-osn-bench
|
||||||
|
#:start-developer-osn-bench))
|
||||||
|
|||||||
445
src/ui-utils.lisp
Normal file
445
src/ui-utils.lisp
Normal file
@ -0,0 +1,445 @@
|
|||||||
|
;;;; OpenScenarioNext --- OpenScenario Language Design
|
||||||
|
;;;; This is copyrighted software. See documentation for terms.
|
||||||
|
;;;;
|
||||||
|
;;;; ui-utils.lisp --- User Interface Utilities
|
||||||
|
;;;;
|
||||||
|
;;;; $Id$
|
||||||
|
|
||||||
|
(cl:in-package #:openscenarionext-bench)
|
||||||
|
|
||||||
|
;;;; %File Description:
|
||||||
|
;;;;
|
||||||
|
;;;; Contains generic parts of the user interface code
|
||||||
|
;;;;
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; Progress indication
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(define-condition osn-bench-progress (condition)
|
||||||
|
((system :initarg :system :reader osn-bench-progress-system)
|
||||||
|
(message :initarg :message :initform nil :reader osn-bench-progress-message)))
|
||||||
|
|
||||||
|
(define-condition osn-bench-progress-range (osn-bench-progress)
|
||||||
|
((new-range :initarg :new-range :reader osn-bench-progress-new-range)))
|
||||||
|
|
||||||
|
(define-condition osn-bench-major-progress (osn-bench-progress)
|
||||||
|
((absolute :initarg :absolute :initform nil :reader osn-bench-progress-absolute)))
|
||||||
|
|
||||||
|
(define-condition osn-bench-minor-progress (osn-bench-progress)
|
||||||
|
())
|
||||||
|
|
||||||
|
(defun note-progress-range (system new-range &rest initargs)
|
||||||
|
(apply #'signal 'osn-bench-progress-range :system system :new-range new-range initargs))
|
||||||
|
|
||||||
|
(defun note-major-progress (system &rest initargs)
|
||||||
|
(apply #'signal 'osn-bench-major-progress :system system initargs))
|
||||||
|
|
||||||
|
(defun note-minor-progress (system &rest initargs)
|
||||||
|
(apply #'signal 'osn-bench-minor-progress :system system initargs))
|
||||||
|
|
||||||
|
(capi:define-interface progress-dialog ()
|
||||||
|
((action :initarg :action :initform "Processing...")
|
||||||
|
(initial-message :initarg :initial-message :initform ""))
|
||||||
|
(:panes
|
||||||
|
(action-message capi:title-pane :text action)
|
||||||
|
(progress-bar capi:progress-bar :start 0 :end 1)
|
||||||
|
(progress-message capi:title-pane :text initial-message)
|
||||||
|
(button-panel capi:push-button-panel
|
||||||
|
:items '("Abort") :callbacks (list #'capi:abort-dialog)
|
||||||
|
:cancel-button "Abort" :test-function #'string=))
|
||||||
|
(:layouts
|
||||||
|
(progress-layout
|
||||||
|
capi:column-layout
|
||||||
|
'(progress-bar progress-message)
|
||||||
|
:adjust :center)
|
||||||
|
(bottom-layout
|
||||||
|
capi:column-layout
|
||||||
|
'(progress-layout button-panel)
|
||||||
|
:adjust :right)
|
||||||
|
(main-layout
|
||||||
|
capi:column-layout
|
||||||
|
'(action-message bottom-layout)
|
||||||
|
:adjust :left))
|
||||||
|
(:default-initargs
|
||||||
|
:layout 'main-layout
|
||||||
|
:best-width 500
|
||||||
|
:title "Processing..."))
|
||||||
|
|
||||||
|
(defun update-progress-dialog (dialog condition)
|
||||||
|
(with-slots (progress-bar progress-message) dialog
|
||||||
|
(when (typep condition '(or osn-bench-progress-range osn-bench-major-progress))
|
||||||
|
(capi:apply-in-pane-process progress-bar
|
||||||
|
(lambda ()
|
||||||
|
(etypecase condition
|
||||||
|
(osn-bench-progress-range
|
||||||
|
(setf (capi:range-end progress-bar)
|
||||||
|
(if (eq t (osn-bench-progress-new-range condition))
|
||||||
|
(1+ (capi:range-end progress-bar))
|
||||||
|
(osn-bench-progress-new-range condition))))
|
||||||
|
(osn-bench-major-progress
|
||||||
|
(if (osn-bench-progress-absolute condition)
|
||||||
|
(setf (capi:range-slug-start progress-bar)
|
||||||
|
(osn-bench-progress-absolute condition))
|
||||||
|
(incf (capi:range-slug-start progress-bar))))))))
|
||||||
|
(when (osn-bench-progress-message condition)
|
||||||
|
(capi:apply-in-pane-process progress-message
|
||||||
|
(lambda ()
|
||||||
|
(setf (capi:title-pane-text progress-message)
|
||||||
|
(osn-bench-progress-message condition)))))))
|
||||||
|
|
||||||
|
(defmacro with-progress-indication ((system &key owner (title "Processing...") action initial-message)
|
||||||
|
&body body)
|
||||||
|
(lispworks:with-unique-names (updater-name condition progress-dialog abort-mailbox
|
||||||
|
result-mailbox progress-process throw-tag results)
|
||||||
|
`(let* ((,progress-dialog (make-instance 'progress-dialog
|
||||||
|
:action ,action :title ,title
|
||||||
|
:initial-message ,(or initial-message "")))
|
||||||
|
(,abort-mailbox (mp:make-mailbox))
|
||||||
|
(,result-mailbox (mp:make-mailbox)))
|
||||||
|
(flet ((,updater-name (,condition)
|
||||||
|
(when (eq (osn-bench-progress-system ,condition) ',system)
|
||||||
|
(when (not (mp:mailbox-empty-p ,abort-mailbox))
|
||||||
|
(mp:mailbox-read ,abort-mailbox)
|
||||||
|
(throw ',throw-tag nil))
|
||||||
|
(update-progress-dialog ,progress-dialog ,condition))))
|
||||||
|
(let ((,progress-process
|
||||||
|
(mp:process-run-function "Progress Indicator Worker" ()
|
||||||
|
(lambda ()
|
||||||
|
(sleep 0.5)
|
||||||
|
(let (,results)
|
||||||
|
(mp:ensure-process-cleanup
|
||||||
|
(lambda (proc)
|
||||||
|
(declare (ignore proc))
|
||||||
|
(if (mp:mailbox-empty-p ,abort-mailbox)
|
||||||
|
(capi:execute-with-interface ,progress-dialog #'capi:exit-dialog t)
|
||||||
|
(mp:mailbox-read ,abort-mailbox))
|
||||||
|
(mp:mailbox-send ,result-mailbox ,results)))
|
||||||
|
(handler-case
|
||||||
|
(setq ,results
|
||||||
|
(multiple-value-list
|
||||||
|
(catch ',throw-tag
|
||||||
|
(handler-bind ((osn-bench-progress #',updater-name))
|
||||||
|
,@body))))
|
||||||
|
(serious-condition (c)
|
||||||
|
(setq ,results c))))))))
|
||||||
|
(setf (mp:mailbox-reader-process ,abort-mailbox) ,progress-process)
|
||||||
|
(if (capi:display-dialog ,progress-dialog ,@(when owner `(:owner ,owner)))
|
||||||
|
(let ((results (mp:mailbox-read ,result-mailbox)))
|
||||||
|
(if (listp results)
|
||||||
|
(values-list results)
|
||||||
|
(error results)))
|
||||||
|
(progn
|
||||||
|
(mp:mailbox-send ,abort-mailbox t)
|
||||||
|
(mp:mailbox-read ,result-mailbox "Waiting for Worker Shutdown" 2)
|
||||||
|
(when (mp:process-alive-p ,progress-process)
|
||||||
|
(mp:process-kill ,progress-process))
|
||||||
|
(invoke-restart (find-restart 'abort)))))))))
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; Standard Viewers
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(capi:define-interface document-interface ()
|
||||||
|
((document-kind :initform "Document Interface"
|
||||||
|
:reader document-interface-document-kind)
|
||||||
|
(document-icon :initform nil
|
||||||
|
:reader document-interface-document-icon)
|
||||||
|
(source :initarg :source :initform nil
|
||||||
|
:accessor document-interface-source)
|
||||||
|
(dirty-p :initarg :dirty-p :initform nil
|
||||||
|
:accessor document-interface-dirty-p))
|
||||||
|
(:default-initargs
|
||||||
|
:confirm-destroy-function 'document-interface-confirm-destroy-function))
|
||||||
|
|
||||||
|
(defmethod document-interface-confirm-destroy-function ((interface document-interface))
|
||||||
|
(or (not (document-interface-dirty-p interface))
|
||||||
|
(multiple-value-bind (save-p quit-p)
|
||||||
|
(capi:prompt-for-confirmation
|
||||||
|
"Document contains unsaved changes. Do you want to save those changes?"
|
||||||
|
:cancel-button t :default-button :cancel :owner interface)
|
||||||
|
(cond
|
||||||
|
((not quit-p) nil)
|
||||||
|
(save-p
|
||||||
|
(document-interface-save interface)
|
||||||
|
(not (document-interface-dirty-p interface)))
|
||||||
|
(t
|
||||||
|
t)))))
|
||||||
|
|
||||||
|
(defmethod document-interface-save-p ((interface document-interface))
|
||||||
|
(document-interface-dirty-p interface))
|
||||||
|
|
||||||
|
(defmethod touch-document-interface (interface)
|
||||||
|
(setf (document-interface-dirty-p interface) t
|
||||||
|
(capi:interface-title interface) (document-interface-title interface)))
|
||||||
|
|
||||||
|
(defmethod untouch-document-interface (interface)
|
||||||
|
(setf (document-interface-dirty-p interface) nil
|
||||||
|
(capi:interface-title interface) (document-interface-title interface)))
|
||||||
|
|
||||||
|
(defgeneric document-interface-title-details (interface))
|
||||||
|
|
||||||
|
(defmethod document-interface-title-details ((interface document-interface)))
|
||||||
|
|
||||||
|
(defmethod document-interface-title ((interface document-interface))
|
||||||
|
(format nil "~A for ~:[Unnamed~;~:*~A~]~@[~A~]~:[~;*~]"
|
||||||
|
(when (slot-boundp interface 'document-kind)
|
||||||
|
(document-interface-document-kind interface))
|
||||||
|
(when (slot-boundp interface 'source)
|
||||||
|
(when (document-interface-source interface)
|
||||||
|
(file-namestring (document-interface-source interface))))
|
||||||
|
(document-interface-title-details interface)
|
||||||
|
(when (slot-boundp interface 'dirty-p)
|
||||||
|
(document-interface-dirty-p interface))))
|
||||||
|
|
||||||
|
(defmethod shared-initialize :after
|
||||||
|
((instance document-interface) slot-names &rest initargs)
|
||||||
|
(setf (capi:interface-title instance)
|
||||||
|
(document-interface-title instance)))
|
||||||
|
|
||||||
|
(defmethod capi:interface-display :after ((interface document-interface))
|
||||||
|
(when (document-interface-document-icon interface)
|
||||||
|
(let* ((icon-path (document-interface-document-icon interface))
|
||||||
|
(small-name (format nil "~A-16" (pathname-name icon-path)))
|
||||||
|
(large-name (format nil "~A-32" (pathname-name icon-path)))
|
||||||
|
(handle (capi:simple-pane-handle interface)))
|
||||||
|
#+(or)
|
||||||
|
(win32:send-message handle win32:wm_seticon 0
|
||||||
|
(get-icon-image small-name icon-path 16 16))
|
||||||
|
#+(or)
|
||||||
|
(win32:send-message handle win32:wm_seticon 1
|
||||||
|
(get-icon-image large-name icon-path 32 32)))))
|
||||||
|
|
||||||
|
(defgeneric document-interface-save (interface))
|
||||||
|
|
||||||
|
(defgeneric document-interface-save-as (interface))
|
||||||
|
|
||||||
|
(defgeneric document-interface-save-as-dialog (interface))
|
||||||
|
|
||||||
|
(defgeneric document-interface-save-internal (interface pathname))
|
||||||
|
|
||||||
|
(defmethod document-interface-save-internal :after ((interface document-interface) pathname)
|
||||||
|
(untouch-document-interface interface))
|
||||||
|
|
||||||
|
(defmethod document-interface-save ((interface document-interface))
|
||||||
|
(if (document-interface-source interface)
|
||||||
|
(capi:with-busy-interface (interface)
|
||||||
|
(document-interface-save-internal interface (document-interface-source interface)))
|
||||||
|
(document-interface-save-as interface)))
|
||||||
|
|
||||||
|
(defmethod document-interface-save-as ((interface document-interface))
|
||||||
|
(multiple-value-bind (pathname ok)
|
||||||
|
(document-interface-save-as-dialog interface)
|
||||||
|
(when ok
|
||||||
|
(capi:with-busy-interface (interface)
|
||||||
|
(document-interface-save-internal interface pathname)
|
||||||
|
(setf (document-interface-source interface) pathname
|
||||||
|
(capi:interface-title interface) (document-interface-title interface))))))
|
||||||
|
|
||||||
|
(defmethod document-interface-refresh ((interface document-interface))
|
||||||
|
(when (and (document-interface-source interface)
|
||||||
|
(or (not (document-interface-dirty-p interface))
|
||||||
|
(capi:prompt-for-confirmation
|
||||||
|
"Document contains unsaved changes. Do you want to discard those changes?" :owner interface)))
|
||||||
|
(handler-case
|
||||||
|
(let* ((warnings nil)
|
||||||
|
(entity
|
||||||
|
(with-progress-indication (:project-parser
|
||||||
|
:owner interface
|
||||||
|
:action (format nil "Refreshing from File ~A:" (document-interface-source interface)))
|
||||||
|
(hcl:with-heavy-allocation
|
||||||
|
(hcl:block-promotion
|
||||||
|
(handler-bind
|
||||||
|
((conditions:stack-overflow
|
||||||
|
#'(lambda (c)
|
||||||
|
(and (< (hcl:current-stack-length)
|
||||||
|
250000)
|
||||||
|
(continue c))))
|
||||||
|
(osn-user-warning
|
||||||
|
#'(lambda (c)
|
||||||
|
(push c warnings)
|
||||||
|
(muffle-warning c))))
|
||||||
|
(document-interface-refresh-reader interface (document-interface-source interface))))))))
|
||||||
|
(setq warnings (nreverse warnings))
|
||||||
|
(document-interface-refresh-internal interface entity warnings)
|
||||||
|
(when warnings
|
||||||
|
(capi:display-message-on-screen
|
||||||
|
(capi:convert-to-screen nil)
|
||||||
|
"~D Import Warning~:P occurred during Import, see the Import Warnings Tab for Details!"
|
||||||
|
(length warnings))))
|
||||||
|
(serious-condition (c)
|
||||||
|
(capi:display-message-on-screen
|
||||||
|
(capi:convert-to-screen nil)
|
||||||
|
"Could not read file ~A: ~A" (document-interface-source interface) c)))))
|
||||||
|
|
||||||
|
(defgeneric document-interface-refresh-reader (interface pathname))
|
||||||
|
|
||||||
|
(defgeneric document-interface-refresh-internal (interface entity warnings))
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; Viewer Warnings
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(capi:define-interface viewer-warnings-mixin ()
|
||||||
|
((viewer-warnings :initarg :warnings :initform nil :reader viewer-warnings)
|
||||||
|
(viewer-warnings-kind :initarg :warnings-kind :initform "Import Warning"
|
||||||
|
:reader viewer-warnings-kind)
|
||||||
|
(viewer-warnings-columns :initarg :warnings-columns :initform '((:title "Type") (:title "Context") (:title "Text"))
|
||||||
|
:reader viewer-warnings-columns)
|
||||||
|
(viewer-warnings-readers :initarg :warnings-readers :initform (list #'type-of #'osn-condition-context #'osn-condition-short-string)
|
||||||
|
:reader viewer-warnings-readers)
|
||||||
|
(viewer-warnings-text-function :initarg :warnings-text-function
|
||||||
|
:initform #'princ-to-string
|
||||||
|
:reader viewer-warnings-text-function))
|
||||||
|
(:panes
|
||||||
|
(viewer-warnings-pane
|
||||||
|
capi:multi-column-list-panel
|
||||||
|
:title (format nil "~As:" viewer-warnings-kind)
|
||||||
|
:items viewer-warnings
|
||||||
|
:interaction :single-selection
|
||||||
|
:columns viewer-warnings-columns
|
||||||
|
:column-function
|
||||||
|
(lambda (entry)
|
||||||
|
(loop for reader in viewer-warnings-readers
|
||||||
|
collect (funcall reader entry)))
|
||||||
|
:callback-type :data
|
||||||
|
:selection-callback
|
||||||
|
(lambda (entry)
|
||||||
|
(setf (capi:display-pane-text viewer-warnings-text-pane)
|
||||||
|
(capi:wrap-text (funcall viewer-warnings-text-function entry) 120))))
|
||||||
|
(viewer-warnings-text-pane
|
||||||
|
capi:display-pane
|
||||||
|
:title (format nil "~A Text:" viewer-warnings-kind)
|
||||||
|
:text (if viewer-warnings (capi:wrap-text (funcall viewer-warnings-text-function (first viewer-warnings)) 120) "")
|
||||||
|
:visible-max-width nil
|
||||||
|
:visible-min-width nil
|
||||||
|
:visible-max-height nil
|
||||||
|
:visible-min-height nil))
|
||||||
|
(:layouts
|
||||||
|
(viewer-warnings-layout
|
||||||
|
capi:column-layout
|
||||||
|
'(viewer-warnings-pane :divider viewer-warnings-text-pane)
|
||||||
|
:ratios '(70 nil 30))))
|
||||||
|
|
||||||
|
(defmethod export-viewer-warnings-to-csv ((viewer viewer-warnings-mixin))
|
||||||
|
(multiple-value-bind (pathname ok)
|
||||||
|
(capi:prompt-for-file (format nil "Export ~A To CSV" (viewer-warnings-kind viewer)) :operation :save
|
||||||
|
:filters '("CSV Files" "*.CSV")
|
||||||
|
:filter "*.CSV")
|
||||||
|
(when ok
|
||||||
|
(capi:with-busy-interface (viewer)
|
||||||
|
(with-open-file (stream pathname #+(or) (ensure-pathname-type pathname "csv")
|
||||||
|
:external-format :utf-8
|
||||||
|
:element-type :default
|
||||||
|
:direction :output :if-exists :supersede)
|
||||||
|
(loop with columns = (viewer-warnings-columns viewer)
|
||||||
|
with readers = (viewer-warnings-readers viewer)
|
||||||
|
for warning in (viewer-warnings viewer)
|
||||||
|
do
|
||||||
|
(format stream "~{\"~A\"~^,~}~%" (mapcar #'(lambda (reader) (funcall reader warning)) readers))
|
||||||
|
initially
|
||||||
|
(format stream "~{\"~A\"~^,~}~%" (mapcar #'(lambda (column) (getf column :title)) columns))))))))
|
||||||
|
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; File Lists
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(capi:define-interface file-selection-list ()
|
||||||
|
((files-title :initarg :files-title :initform "Files:")
|
||||||
|
(files-add :initarg :files-add :initform "Add Files:")
|
||||||
|
(filter :initarg :filter :initform "*.*")
|
||||||
|
(filters :initarg :filters :initform '("All Files" "*.*"))
|
||||||
|
(ok-check :initarg :ok-check :initform 'probe-file))
|
||||||
|
(:panes
|
||||||
|
(files-list
|
||||||
|
capi:list-panel
|
||||||
|
:title files-title
|
||||||
|
:interaction :extended-selection
|
||||||
|
:callback-type :interface
|
||||||
|
:enabled (capi:simple-pane-enabled capi:interface)
|
||||||
|
:items nil
|
||||||
|
:visible-min-height 80
|
||||||
|
:selection-callback
|
||||||
|
#'(lambda (interface)
|
||||||
|
(if (capi:choice-selected-items files-list)
|
||||||
|
(capi:set-button-panel-enabled-items files-buttons
|
||||||
|
:enable '(:remove))
|
||||||
|
(capi:set-button-panel-enabled-items files-buttons
|
||||||
|
:disable '(:remove)))
|
||||||
|
(capi:redisplay-interface interface))
|
||||||
|
:extend-callback
|
||||||
|
#'(lambda (interface)
|
||||||
|
(if (capi:choice-selected-items files-list)
|
||||||
|
(capi:set-button-panel-enabled-items files-buttons
|
||||||
|
:enable '(:remove))
|
||||||
|
(capi:set-button-panel-enabled-items files-buttons
|
||||||
|
:disable '(:remove)))
|
||||||
|
(capi:redisplay-interface interface))
|
||||||
|
:retract-callback
|
||||||
|
#'(lambda (interface)
|
||||||
|
(if (capi:choice-selected-items files-list)
|
||||||
|
(capi:set-button-panel-enabled-items files-buttons
|
||||||
|
:enable '(:remove))
|
||||||
|
(capi:set-button-panel-enabled-items files-buttons
|
||||||
|
:disable '(:remove)))
|
||||||
|
(capi:redisplay-interface interface)))
|
||||||
|
(files-buttons
|
||||||
|
capi:push-button-panel
|
||||||
|
:layout-class 'capi:column-layout
|
||||||
|
:items '(:add :remove)
|
||||||
|
:enabled (capi:simple-pane-enabled capi:interface)
|
||||||
|
:print-function #'string-capitalize
|
||||||
|
:callback-type :element-data
|
||||||
|
:selection-callback
|
||||||
|
#'(lambda (element item)
|
||||||
|
(ecase item
|
||||||
|
(:add
|
||||||
|
(multiple-value-bind (files ok)
|
||||||
|
(capi:prompt-for-files
|
||||||
|
files-add
|
||||||
|
:operation :open
|
||||||
|
:if-does-not-exist :error
|
||||||
|
:filters filters
|
||||||
|
:filter filter
|
||||||
|
:ok-check ok-check
|
||||||
|
:owner (capi:element-interface element))
|
||||||
|
(when ok
|
||||||
|
(capi:append-items files-list files))))
|
||||||
|
(:remove
|
||||||
|
(capi:remove-items files-list (capi:choice-selected-items files-list))
|
||||||
|
(capi:set-button-panel-enabled-items element :disable '(:remove)))))))
|
||||||
|
(:layouts
|
||||||
|
(layout
|
||||||
|
capi:row-layout
|
||||||
|
'(files-list files-buttons))))
|
||||||
|
|
||||||
|
#+(or)
|
||||||
|
(defmethod shared-initialize :after ((instance file-selection-list) slot-names &rest initargs)
|
||||||
|
(when nil
|
||||||
|
(with-slots (files-buttons) instance
|
||||||
|
(capi:set-button-panel-enabled-items files-buttons :disable '(:remove)))))
|
||||||
|
|
||||||
|
(defmethod (setf capi:simple-pane-enabled) :after (newvalue (pane file-selection-list))
|
||||||
|
(with-slots (files-list files-buttons) pane
|
||||||
|
(setf (capi:simple-pane-enabled files-list) newvalue
|
||||||
|
(capi:simple-pane-enabled files-buttons) newvalue)
|
||||||
|
(when newvalue
|
||||||
|
(unless (capi:choice-selection files-list)
|
||||||
|
(capi:set-button-panel-enabled-items files-buttons :disable '(:remove))))))
|
||||||
|
|
||||||
|
(defmethod file-selection-list-files ((instance file-selection-list))
|
||||||
|
(with-slots (files-list) instance
|
||||||
|
(capi:collection-items files-list)))
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; External Viewer
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(defun open-in-external-viewer (pathname)
|
||||||
|
#+mswindows
|
||||||
|
(system:call-system (format nil "start \"\" ~S" (namestring pathname))
|
||||||
|
:wait nil)
|
||||||
|
#+linux
|
||||||
|
(system:call-system (format nil "xdg-open ~S" (namestring pathname))
|
||||||
|
:wait nil))
|
||||||
247
src/win-ui.lisp
Normal file
247
src/win-ui.lisp
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
;;;; OpenScenarioNext --- OpenScenario Language Design
|
||||||
|
;;;; This is copyrighted software. See documentation for terms.
|
||||||
|
;;;;
|
||||||
|
;;;; win-ui.lisp --- Windows UI Code
|
||||||
|
|
||||||
|
(cl:in-package #:openscenarionext-bench)
|
||||||
|
|
||||||
|
;;;; %File Description:
|
||||||
|
;;;;
|
||||||
|
;;;; Contains the Windows specific parts of the user interface code
|
||||||
|
;;;;
|
||||||
|
|
||||||
|
(capi:define-interface application-interface (capi:document-frame)
|
||||||
|
()
|
||||||
|
(:menus
|
||||||
|
(file-menu
|
||||||
|
"File"
|
||||||
|
((:component
|
||||||
|
((:menu
|
||||||
|
(("OSN File"
|
||||||
|
:callback 'application-interface-new-osn
|
||||||
|
:callback-type :interface))
|
||||||
|
:title "New")
|
||||||
|
("Open ..."
|
||||||
|
:accelerator "accelerator-o"
|
||||||
|
:callback 'application-interface-open
|
||||||
|
:callback-type :interface)))
|
||||||
|
(:component
|
||||||
|
(("Quit OSN Bench"
|
||||||
|
:accelerator "accelerator-q"
|
||||||
|
:callback 'quit-osn-bench
|
||||||
|
:callback-type :interface)))))
|
||||||
|
(help-menu
|
||||||
|
"Help"
|
||||||
|
((:component
|
||||||
|
(((format nil "About OSN Bench")
|
||||||
|
:callback 'application-interface-about
|
||||||
|
:callback-type :none))))))
|
||||||
|
(:menu-bar file-menu capi:windows-menu help-menu)
|
||||||
|
(:layouts
|
||||||
|
(main-layout capi:column-layout (list (slot-value capi:interface 'capi:container))))
|
||||||
|
(:default-initargs
|
||||||
|
:title "OSN Bench"
|
||||||
|
:confirm-destroy-function 'confirm-quit-osn-bench
|
||||||
|
:destroy-callback 'destroy-application-interface-hook
|
||||||
|
:layout 'main-layout
|
||||||
|
:auto-menus :generated
|
||||||
|
:best-width 1000
|
||||||
|
:best-height 700))
|
||||||
|
|
||||||
|
(defmethod capi:merge-menu-bars ((frame application-interface) document)
|
||||||
|
(loop with special-menus = (list (slot-value frame 'capi:windows-menu)
|
||||||
|
(slot-value frame 'help-menu))
|
||||||
|
with frame-file-menu = (slot-value frame 'file-menu)
|
||||||
|
with document-file-menu = (when document (slot-value document 'file-menu))
|
||||||
|
for menu in (capi:interface-menu-bar-items frame)
|
||||||
|
when (and (eq menu frame-file-menu) document-file-menu)
|
||||||
|
do (setq menu document-file-menu)
|
||||||
|
when (member menu special-menus)
|
||||||
|
append (when document (remove document-file-menu (capi:interface-menu-bar-items document)))
|
||||||
|
and do (setq special-menus nil)
|
||||||
|
collect menu))
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; Global callbacks
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(defun derive-main-interface (interface)
|
||||||
|
(typecase interface
|
||||||
|
(application-interface interface)
|
||||||
|
(t (capi:element-interface (capi:convert-to-screen interface)))))
|
||||||
|
|
||||||
|
(defun find-main-interface ()
|
||||||
|
(capi:locate-interface 'application-interface))
|
||||||
|
|
||||||
|
(defun derive-main-interface-screen (interface)
|
||||||
|
(capi:document-frame-container (derive-main-interface interface)))
|
||||||
|
|
||||||
|
(capi:define-interface about-dialog ()
|
||||||
|
()
|
||||||
|
(:panes
|
||||||
|
(button-panel
|
||||||
|
capi:push-button-panel
|
||||||
|
:items '("Ok")
|
||||||
|
:default-button "Ok"
|
||||||
|
:cancel-button "Ok"
|
||||||
|
:test-function #'string=
|
||||||
|
:x 708 :y 10
|
||||||
|
:layout-class 'capi:column-layout
|
||||||
|
:layout-args '(:adjust :right)
|
||||||
|
:callback-type :data
|
||||||
|
:callbacks (list #'capi:exit-dialog)))
|
||||||
|
(:layouts
|
||||||
|
(version-layout
|
||||||
|
capi:column-layout
|
||||||
|
(list
|
||||||
|
"OpenScenarioNext Bench"
|
||||||
|
"(c) 2018 - 2019 PMSF IT Consulting Pierre R. Mai"
|
||||||
|
(if *ob-developer-edition*
|
||||||
|
"PMSF Developer License"
|
||||||
|
"Demo License"))
|
||||||
|
:gap 5)
|
||||||
|
(license-layout
|
||||||
|
capi:grid-layout
|
||||||
|
(if *ob-developer-edition*
|
||||||
|
(list "Serial Number:" "00000000042"
|
||||||
|
"Expiry Date:" "Permanent")
|
||||||
|
(list
|
||||||
|
"Serial Number:" "00000000042"
|
||||||
|
"Expiry Date:" "Permanent"))
|
||||||
|
:columns 2 :x-gap 10 :y-gap 5)
|
||||||
|
(info-layout
|
||||||
|
capi:column-layout
|
||||||
|
'(version-layout license-layout)
|
||||||
|
:gap 5
|
||||||
|
:x 422 :y 400)
|
||||||
|
(main-layout
|
||||||
|
capi:pinboard-layout
|
||||||
|
(list
|
||||||
|
'info-layout
|
||||||
|
'button-panel)
|
||||||
|
:input-model (list
|
||||||
|
(list '(:button-1 :press)
|
||||||
|
(lambda (self x y)
|
||||||
|
(declare (ignore self x y))
|
||||||
|
(capi:exit-dialog t))))))
|
||||||
|
(:default-initargs
|
||||||
|
:layout 'main-layout
|
||||||
|
:window-styles '(:borderless :internal-borderless :shadowed)))
|
||||||
|
|
||||||
|
(defun application-interface-about ()
|
||||||
|
(capi:display-dialog (make-instance 'about-dialog) :position-relative-to nil))
|
||||||
|
|
||||||
|
(defun destroy-application-interface-hook (interface)
|
||||||
|
(declare (ignore interface)))
|
||||||
|
|
||||||
|
(defun quit-osn-bench (interface)
|
||||||
|
(when (confirm-quit-osn-bench (derive-main-interface interface))
|
||||||
|
(capi:destroy (derive-main-interface interface))))
|
||||||
|
|
||||||
|
(defun confirm-quit-osn-bench (interface)
|
||||||
|
(capi:prompt-for-confirmation
|
||||||
|
(format nil "~:[~;Documents with unsaved changes.~2%~]Really exit OSN Bench?"
|
||||||
|
(some #'document-interface-dirty-p
|
||||||
|
(capi:collect-interfaces 'document-interface
|
||||||
|
:screen (capi:document-frame-container interface))))
|
||||||
|
:owner interface))
|
||||||
|
|
||||||
|
(defun probe-file-for-open (pathname)
|
||||||
|
(cond
|
||||||
|
((string-equal (pathname-type pathname) "osn")
|
||||||
|
(values "OpenScenarioNext"
|
||||||
|
(lambda (osn warnings pathname)
|
||||||
|
(declare (ignore warnings))
|
||||||
|
(make-instance 'osn-viewer :source (pathname pathname)
|
||||||
|
:osn-buffer osn))
|
||||||
|
#'editor:find-file-buffer))
|
||||||
|
(t
|
||||||
|
nil)))
|
||||||
|
|
||||||
|
(defun application-interface-open (interface &optional pathname)
|
||||||
|
(setq interface (derive-main-interface interface))
|
||||||
|
(multiple-value-bind (pathnames ok)
|
||||||
|
(if pathname
|
||||||
|
(values (list pathname) t)
|
||||||
|
(capi:prompt-for-files "File"
|
||||||
|
:operation :open
|
||||||
|
:if-does-not-exist :error
|
||||||
|
:filters '("OSN Files" "*.osn"
|
||||||
|
"Known Files" "*.osn"
|
||||||
|
"All Files" "*.*")
|
||||||
|
:filter "*.osn"
|
||||||
|
:ok-check 'probe-file
|
||||||
|
:owner interface))
|
||||||
|
(when ok
|
||||||
|
(dolist (pathname pathnames)
|
||||||
|
(block nil
|
||||||
|
(multiple-value-bind (kind viewer-fun reader-fun)
|
||||||
|
(probe-file-for-open pathname)
|
||||||
|
(unless kind
|
||||||
|
(capi:display-message-on-screen
|
||||||
|
(capi:convert-to-screen nil)
|
||||||
|
"Unknown file type for ~A!" pathname)
|
||||||
|
(return nil))
|
||||||
|
(capi:with-busy-interface (interface)
|
||||||
|
(handler-case
|
||||||
|
(let* ((warnings nil)
|
||||||
|
(entity
|
||||||
|
(with-progress-indication (:project-parser
|
||||||
|
:owner interface
|
||||||
|
:action (format nil "Importing ~A File ~A:" kind pathname))
|
||||||
|
(hcl:with-heavy-allocation
|
||||||
|
(hcl:block-promotion
|
||||||
|
(handler-bind
|
||||||
|
((conditions:stack-overflow
|
||||||
|
#'(lambda (c)
|
||||||
|
(and (< (hcl:current-stack-length)
|
||||||
|
250000)
|
||||||
|
(continue c))))
|
||||||
|
(osn-user-warning
|
||||||
|
#'(lambda (c)
|
||||||
|
(push c warnings)
|
||||||
|
(muffle-warning c))))
|
||||||
|
(funcall reader-fun pathname)))))))
|
||||||
|
(setq warnings (nreverse warnings))
|
||||||
|
(capi:display
|
||||||
|
(funcall viewer-fun entity warnings pathname)
|
||||||
|
:screen (capi:document-frame-container interface))
|
||||||
|
(when warnings
|
||||||
|
(capi:display-message-on-screen
|
||||||
|
(capi:convert-to-screen nil)
|
||||||
|
"~D Import Warning~:P occurred during Import, see the Import Warnings Tab for Details!"
|
||||||
|
(length warnings))))
|
||||||
|
(serious-condition (c)
|
||||||
|
(capi:display-message-on-screen
|
||||||
|
(capi:convert-to-screen nil)
|
||||||
|
"Could not read file ~A: ~A" pathname c))))))))))
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; Main Entry Point
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(defun start-osn-bench ()
|
||||||
|
(sleep 0.1)
|
||||||
|
(win32:dismiss-splash-screen t)
|
||||||
|
(setq *ob-developer-edition* nil)
|
||||||
|
(internal-start-osn-bench))
|
||||||
|
|
||||||
|
(defun start-developer-osn-bench ()
|
||||||
|
(setq *ob-developer-edition* t)
|
||||||
|
(internal-start-osn-bench))
|
||||||
|
|
||||||
|
(defun internal-start-osn-bench ()
|
||||||
|
(let ((app-interface
|
||||||
|
(make-instance 'application-interface
|
||||||
|
:top-level-hook
|
||||||
|
(lambda (thunk interface)
|
||||||
|
(handler-bind ((condition #'(lambda (c) (default-condition-handler c interface))))
|
||||||
|
(funcall thunk))))))
|
||||||
|
(capi:display app-interface)
|
||||||
|
(when (and (rest system:*line-arguments-list*)
|
||||||
|
(string= (first (rest system:*line-arguments-list*)) "--open"))
|
||||||
|
(loop for filename in (rest (rest system:*line-arguments-list*))
|
||||||
|
for path = (probe-file filename)
|
||||||
|
do
|
||||||
|
(when path
|
||||||
|
(application-interface-open app-interface path))))))
|
||||||
Reference in New Issue
Block a user