Update of /project/rjain-utils/cvsroot/formulate/src/clim-ui In directory cl-net:/tmp/cvs-serv31147/src/clim-ui
Modified Files: application.lisp formulate.clim-ui.asd objects.lisp variables.lisp Added Files: classes.lisp Log Message: usability enhancements
separate class definer into a separate application frame and make it work
--- /project/rjain-utils/cvsroot/formulate/src/clim-ui/application.lisp 2009/11/24 10:06:47 1.2 +++ /project/rjain-utils/cvsroot/formulate/src/clim-ui/application.lisp 2009/12/25 21:03:22 1.3 @@ -1,11 +1,18 @@ (in-package :formulate.clim-ui)
+(defvar *document-package-counter* 0) + +(defun make-document-package () + (make-package (format nil "Document ~A" (incf *document-package-counter*)) + :use '(common-lisp formulate)))
(define-application-frame formulate () - ((monitored-values :initform (make-array 5 :fill-pointer 0 :adjustable t) + ((document-package :initform (make-document-package) :initarg :document-package :accessor document-package) + (monitored-values :initform (make-array 5 :fill-pointer 0 :adjustable t) :accessor monitored-values)) (:panes (interactor :interactor - :scroll-bars t) + :scroll-bars t + :min-width 400) (monitor :application :scroll-bars t :incremental-redisplay t @@ -16,8 +23,26 @@ monitor interactor)))
+(defmethod shared-initialize :after ((formulate formulate) slots &key) + (setf (frame-pretty-name formulate) + (format nil "Formulate: ~A" (package-name (document-package formulate))))) + +(defmethod default-frame-top-level ((frame formulate) &key &allow-other-keys) + (let ((*package* (document-package frame)) + (*debugger-hook* (if (find-package :clim-debugger) + (find-symbol "DEBUGGER" :clim-debugger) + *debugger-hook*))) + (call-next-method))) + +(define-formulate-command com-import-library ((name 'string)) + (use-package (string-upcase name))) + +;;;; +;;;; DATA MONITOR +;;;; + (defun display-monitor (*application-frame* *standard-output*) - (updating-output (t :unique-id (monitored-values *application-frame*)) + (updating-output (t) (map nil (lambda (item) (display-monitored-value item)) (monitored-values *application-frame*))))
@@ -28,31 +53,25 @@ (defun remove-from-monitor (value *application-frame*) (delete value (monitored-values *application-frame*)))
-(defvar *error-formulator* nil) - (defmacro display-formula-value (location) `(catch 'formula-value-fail (handler-bind ((error #'(lambda (error) (display-formula-error error formulate::*formulating*) (throw 'formula-value-fail nil)))) - (let ((error-source-p (eql *error-formulator* - (let ((formulate::*get-formulator* t)) - ,location))) - (value ,location)) - (when error-source-p - (with-text-face (t :bold) - (with-drawing-options (t :ink +red+) - (write-string ">>>")))) - (present value (presentation-type-of value)) - (when error-source-p - (with-text-face (t :bold) - (with-drawing-options (t :ink +red+) - (write-string "<<<")))))))) + (let* ((value ,location) + (ptype (if (typep (class-of value) 'formulated-class) + 'formulated-object + (presentation-type-of value)))) + (present value ptype)))))
(defmethod frame-standard-output ((frame formulate)) (get-frame-pane frame 'interactor))
+;;;; +;;;; FORMULA ERROR HANDLING +;;;; + (define-presentation-type formula-error () :inherit-from t)
@@ -65,17 +84,26 @@ (print-unreadable-object ((formula-error-error error) stream :type t)))
(defun display-formula-error (error formulator) - (with-output-as-presentation (t - (make-formula-error :error error :formulator formulator) - 'formula-error) + (with-output-as-presentation (t (make-formula-error :error error :formulator formulator) + 'formula-error) (with-text-face (t :italic) (with-drawing-options (t :ink +red+) - (write-char #!) +2 (write-char #!) (prin1 (class-name (class-of error))) (write-char #!)))))
(define-formulate-command com-describe-error ((err 'formula-error :gesture :select)) - (setf *error-formulator* (formula-error-formulator err)) (present (formula-error-error err) t) (format t "~&while computing ~A" (formulate::formulator-formula (formula-error-formulator err)))) + +;;;; +;;;; LAUNCHER ENTRY POINT +;;;; + +(defun run () + (clim-sys:make-process + (lambda () + (clim:run-frame-top-level + (clim:make-application-frame "Formulate" + :frame-class 'formulate.clim-ui:formulate))))) \ No newline at end of file --- /project/rjain-utils/cvsroot/formulate/src/clim-ui/formulate.clim-ui.asd 2009/11/19 01:17:18 1.1 +++ /project/rjain-utils/cvsroot/formulate/src/clim-ui/formulate.clim-ui.asd 2009/12/25 21:03:22 1.2 @@ -3,5 +3,6 @@ ((:file "package") (:file "application" :depends-on ("package")) (:file "variables" :depends-on ("package" "application")) - (:file "objects" :depends-on ("package" "application"))) + (:file "objects" :depends-on ("package" "application")) + (:file "classes" :depends-on ("package" "application"))) :depends-on (:formulate :clim)) --- /project/rjain-utils/cvsroot/formulate/src/clim-ui/objects.lisp 2009/11/24 10:06:47 1.2 +++ /project/rjain-utils/cvsroot/formulate/src/clim-ui/objects.lisp 2009/12/25 21:03:22 1.3 @@ -1,40 +1,16 @@ (in-package :formulate.clim-ui)
-(define-formulate-command (com-define-formulated-class :name "Define Class") - ((name 'symbol :prompt "Name") - (superclasses '(sequence symbol) :default () :prompt "Superclasses") - (slots '(sequence slot-specification) :prompt "Slots")) - (eval `(defclass ,name ,(coerce superclasses 'list) - (,@(coerce slots 'list)) - (:metaclass formulated-class)))) - -(define-presentation-type slot-specification () - :inherit-from 'expression) - -(define-presentation-method accept ((type slot-specification) stream view - &key default) - (let* ((name (if default - (accept 'symbol :prompt "Name" :default (first default)) - (accept 'symbol :prompt "Name"))) - (formula-p (accept 'boolean - :prompt "Formula?" - :default (getf default 'formula-p t) - :default-type 'boolean)) - (initform (accept 'expression :prompt (if formula-p "Formula" "Initial value")))) - `(,name formula-p ,formula-p :initform ,initform))) - (define-formulate-command (com-create-instance :name "Create Instance") - ((class '(or class symbol) :prompt "Class")) - (vector-push-extend (make-instance class) + ((name 'symbol :prompt "Name") + (class '(or class symbol) :prompt "Class")) + (proclaim `(special ,name)) + (setf (symbol-value name) (make-instance class)) + (vector-push-extend name (monitored-values *application-frame*)))
(define-presentation-type formulated-object () :inherit-from t)
-(defmethod display-monitored-value ((object standard-object)) - (fresh-line) - (present object 'formulated-object)) - (define-presentation-type formulated-slot () ;; 3 element list: (slot-value <object> <slot-name>) :inherit-from t) @@ -54,21 +30,22 @@
(define-presentation-method present (object (type formulated-object) stream view &key) - (with-output-as-presentation (stream object 'formulated-object) + (with-output-as-presentation (stream object 'formulated-object :single-box t) (with-output-as-presentation (stream (class-of object) 'class) - (with-text-face (stream :bold) - (prin1 (class-name (class-of object)) stream))) + (with-text-face (stream :bold) + (with-drawing-options (t :ink +blue+) + (prin1 (class-name (class-of object)) stream)))) (fresh-line stream) (formatting-table (stream) (dolist (slot (class-slots (class-of object))) (with-output-as-presentation (stream `(slot-value ,object ',(slot-definition-name slot)) - 'formulated-slot) + 'formulated-slot + :single-box t) (display-slot-as-row object slot stream view))))))
(define-presentation-translator slot-accessor (formulated-slot form formulate) (object) - (format t "translating slot to expression") (values object 'expression t))
(define-formulate-command (com-remove-object :name "Remove Object From Monitor") @@ -77,7 +54,7 @@
(define-formulate-command (com-set-slot-value :name "Set Slot Value") ((expression 'formulated-slot :prompt "Slot" :gesture :select) - (new-value 'form :prompt "New value" :default *unsupplied-argument-marker*)) + (new-value 'form :prompt "New value")) (destructuring-bind (s-v object (q slot)) expression (declare (ignore s-v q)) (setf (slot-value object slot) (eval new-value)))) --- /project/rjain-utils/cvsroot/formulate/src/clim-ui/variables.lisp 2009/11/24 10:06:47 1.2 +++ /project/rjain-utils/cvsroot/formulate/src/clim-ui/variables.lisp 2009/12/25 21:03:22 1.3 @@ -3,10 +3,10 @@ (define-formulate-command (com-define-formulated-variable :name "Define Variable") ((name 'symbol :prompt "Name") (formula-p 'boolean :prompt "Formula?") - (formula 'expression :prompt (if formula-p "Formula" "Initial value")) + (formula 'form :prompt (if formula-p "Formula" "Initial value")) (monitor-p 'boolean :default t :prompt "Show in monitor pane?") - (declarations 'expression :default '() :prompt "Declarations") - (documentation '(or string null) :default nil :prompt "Documentation")) + (declarations 'expression :default '((optimize (speed 1))) :prompt "Declarations") + (documentation '(or string null) :default "" :prompt "Documentation")) (eval `(define-formulated-variable ,name ,formula :formula-p ,formula-p :declare ,declarations :documentation ,documentation)) @@ -15,15 +15,27 @@ (vector-push-extend name (monitored-values *application-frame*)))))
(define-presentation-type formulated-variable () - :inherit-from t) + :inherit-from 'symbol)
(defmethod display-monitored-value ((name symbol)) (fresh-line) - (with-output-as-presentation (t name 'formulated-variable) - (with-text-face (t :bold) - (present name 'symbol)) - (write-string " = ") - (display-formula-value (eval name)))) + (with-output-as-presentation (t name (if (formulated-variable-p name) 'formulated-variable 'symbol) :single-box t) + (formatting-table () + (formatting-row () + (formatting-cell () + (with-text-face (t :bold) + (present name 'symbol)) + (write-string " = ")) + (formatting-cell () + (display-formula-value (eval name))))) + (when (documentation name 'variable) + (fresh-line) + (with-text-face (t :italic) + (with-drawing-options (t :ink +dark-green+) + (filling-output (t) + (write-string (documentation name 'variable))))))) + (terpri) + (terpri))
(define-formulate-command (com-remove-variable :name "Remove Variable From Monitor") ((name 'formulated-variable :prompt "Variable" :gesture :menu)) @@ -31,7 +43,7 @@
(define-formulate-command (com-set-variable :name "Set Variable") ((name 'formulated-variable :gesture :select) - (new-value 'form)) + (new-value 'expression)) (eval `(setf ,name ',new-value)))
(define-formulate-command (com-describe-variable :name "Describe Variable")
--- /project/rjain-utils/cvsroot/formulate/src/clim-ui/classes.lisp 2009/12/25 21:03:22 NONE +++ /project/rjain-utils/cvsroot/formulate/src/clim-ui/classes.lisp 2009/12/25 21:03:22 1.1 (in-package :formulate.clim-ui)
(define-application-frame class-definer () ((formulate-application :initarg :formulate-application :accessor formulate-application) (class-name :initarg :class-name :accessor name) (direct-superclasses :initarg :direct-superclasses :initform () :accessor direct-superclasses) (slots :initarg :direct-slots :initform () :accessor direct-slots) (options :initarg :options :initform '((:metaclass formulated-class)) :accessor options)) (:pointer-documentation t) (:top-level (class-definer-top-level)) (:geometry :width 500 :height 500) (:panes (class :application :scroll-bars t :display-function 'display-class-definition :display-time :command-loop) (interactor :interactor :scroll-bars t)) (:layouts (initial (:fill class) (horizontally (:x-spacing 10 :max-width 1000) (make-pane 'push-button :label "Define Class" :show-as-default t :activate-callback (lambda (gadget) (declare (ignore gadget)) (eval-define-class *application-frame*) (redisplay-frame-pane (formulate-application *application-frame*) 'monitor) (frame-exit *application-frame*))) (make-pane 'push-button :label "Cancel" :activate-callback (lambda (gadget) (declare (ignore gadget)) (frame-exit *application-frame*))))) (interacting (2/5 class) (3/5 interactor))))
(define-formulate-command (com-define-formulated-class :name "Define Class") ((name 'symbol :prompt "Name")) (let ((package *package*) (formulate-application *application-frame*) (dialog-name (format nil "Define Class: ~A" name))) (clim-sys:make-process (lambda () (let ((*package* package)) (run-frame-top-level (apply #'make-application-frame dialog-name :frame-class 'class-definer :formulate-application formulate-application :class-name name (when (find-class name nil) (let ((class (find-class name))) (list :direct-superclasses (mapcar #'class-name (class-direct-superclasses class)) :direct-slots (mapcar #'make-slot-specification (class-direct-slots class)) :options (list (list :metaclass (class-name (class-of class))))))))))) :name dialog-name)))
(defvar *setting-layout* nil)
(defmethod layout-frame ((frame class-definer) &optional width height) (if *setting-layout* nil #+nil ;; TODO need to figure out how to get relayout to happen without resizing frame (allocate-space (frame-top-level-sheet frame) (graft-width (frame-top-level-sheet frame)) (graft-height (frame-top-level-sheet frame))) (if (or width height) (call-next-method) (let* ((sr-initial (compose-space (climi::find-pane-for-layout 'initial frame))) (sr-interacting (compose-space (climi::find-pane-for-layout 'interacting frame))) (combined-sr (space-requirement-combine #'max sr-initial sr-interacting))) (call-next-method frame (space-requirement-width combined-sr) (space-requirement-height combined-sr))))))
(defmethod (setf frame-current-layout) :around (name (frame class-definer)) (let ((*setting-layout* t)) (call-next-method)))
(defun accept-without-interactor (frame type) (with-input-context (type) (object) (loop (read-gesture :stream (get-frame-pane frame 'class))) (t object)))
(defvar *interaction-continuation* nil)
(defun do-interaction () (let* ((interactor (get-frame-pane *application-frame* 'interactor)) (*standard-input* interactor) (*standard-output* interactor) (*query-io* interactor)) (window-clear (get-frame-pane *application-frame* 'interactor)) (unwind-protect (funcall *interaction-continuation*) (setf *interaction-continuation* nil) (setf (frame-current-layout *application-frame*) 'initial))))
(defun get-command () (let ((command (accept-without-interactor *application-frame* `(command :command-table ,(frame-command-table *application-frame*))))) (execute-frame-command *application-frame* command)))
(defun class-definer-top-level (*application-frame*) (redisplay-frame-panes *application-frame* :force-p t) ;; limit scope of changes to *INTERACTION-CONTINUATION* to this ;; specific invocation (let ((*interaction-continuation* nil)) (loop (restart-case (progn (redisplay-frame-panes *application-frame*) (if (print *interaction-continuation*) (do-interaction) (get-command))) (abort () :report "Return to application command loop" (clim-extensions:frame-display-pointer-documentation-string *application-frame* "Command aborted."))))))
(defmacro with-interaction (() &body body) `(progn (setf *interaction-continuation* (lambda () ,@body)) (handler-case ;; the following may exit non-locally back to the top-level loop (setf (frame-current-layout *application-frame*) 'interacting) (climi::frame-layout-changed ())) (do-interaction)))
(defun eval-define-class (definer) (eval `(defclass ,(name definer) ,(direct-superclasses definer) ,(mapcar #'slot-specification-form (direct-slots definer)) ,@(options definer))))
(define-presentation-type slot-specification () :inherit-from 't)
(defstruct (slot-specification (:constructor %make-slot-specification (name &key formula-p initform accessor options))) name formula-p initform accessor options)
(defmethod make-slot-specification ((slotd direct-slot-definition) &rest keys) (declare (ignore keys)) (%make-slot-specification (slot-definition-name slotd) :formula-p (subtypep (formulate::formulator-class slotd) 'formulate::formula-formulator-sink) :initform (slot-definition-initform slotd) :accessor (first (slot-definition-readers slotd)) :options nil))
(defmethod make-slot-specification ((name symbol) &rest keys) (apply #'%make-slot-specification name keys))
(defun slot-specification-form (spec) (list* (slot-specification-name spec) 'formula-p (slot-specification-formula-p spec) :initform (slot-specification-initform spec) :accessor (slot-specification-accessor spec) (slot-specification-options spec)))
(define-presentation-method present ((spec slot-specification) (type slot-specification) *standard-output* view &key) (present (slot-specification-name spec)) (with-text-face (t :italic) (prin1 " Formula?: ")) (present (slot-specification-formula-p spec) 'boolean) (with-text-face (t :italic) (if (slot-specification-formula-p spec) (prin1 " Formula: ") (prin1 " Initial Value: "))) (present (slot-specification-initform spec) 'form) (with-text-face (t :italic) (prin1 " Accessor: ")) (present (slot-specification-accessor spec) 'symbol) (with-text-face (t :italic) (prin1 " Options: ")) (present (slot-specification-options spec) 'form))
(define-presentation-translator peer-accessor (slot-specification form class-definer) (object) (values `(my ,(slot-specification-name object)) 'expression t))
(define-presentation-translator peer-accessor (formulated-slot form class-definer) (object) (values `(my ,(second (third object))) 'expression t))
(define-presentation-method accept ((type slot-specification) *standard-output* view &key default) (let (name formula-p initform accessor options) (accepting-values () (fresh-line) (setf name (apply #'accept 'symbol :prompt "Name" (when default (list :default (slot-specification-name default))))) (terpri) (setf formula-p (accept 'boolean :prompt "Formula?" :default (if default (slot-specification-formula-p default) t))) (terpri) (setf initform (apply #'accept 'expression :prompt (if formula-p "Formula" "Initial Value") :query-identifier :initform (when default (list :default (slot-specification-initform default))))) (terpri) (setf accessor (apply #'accept 'symbol :prompt "Accessor" (when default (list :default (slot-specification-accessor default))))) (terpri) (setf options (accept 'expression :prompt "Options" :default (if default (slot-specification-options default) nil)))) (make-slot-specification name :formula-p formula-p :initform initform :accessor accessor :options options)))
(define-modify-macro nconcf (place &rest lists) nconc)
(defun add-superclass (gadget) (declare (ignore gadget)) (with-interaction () (let ((class (accept 'symbol))) (nconcf (direct-superclasses *application-frame*) (list class)))))
(defun add-slot (gadget) (declare (ignore gadget)) (with-interaction () (let ((slot (accept 'slot-specification))) (nconcf (direct-slots *application-frame*) (list slot)))))
(defun add-option (gadget) (declare (ignore gadget)) (with-interaction () (let ((option (accept 'form))) (nconcf (options *application-frame*) (list option)))))
(define-presentation-type superclass () :inherit-from 'class)
(define-class-definer-command (com-remove-superclass) ((superclass 'superclass :gesture :describe)) (setf (direct-superclasses *application-frame*) (remove superclass (direct-superclasses *application-frame*))))
(define-class-definer-command (com-change-superclass) ((superclass 'superclass :gesture :select)) (with-interaction () (setf (direct-superclasses *application-frame*) (substitute (direct-superclasses *application-frame*) (accept 'symbol :default superclass :prompt "New Superclass") superclass))))
(define-class-definer-command (com-remove-slot) ((slot 'slot-specification :gesture :describe)) (setf (direct-slots *application-frame*) (remove slot (direct-slots *application-frame*))))
(define-class-definer-command (com-change-slot) ((slot 'slot-specification :gesture :select)) (with-interaction () (setf (direct-slots *application-frame*) (substitute (accept 'slot-specification :default slot) slot (direct-slots *application-frame*)))))
(define-presentation-type class-option () :inherit-from 'expression)
(define-presentation-method presentation-typep ((object cons) (type class-option)) (and (symbolp (car object)) (consp (cdr object))))
(define-class-definer-command (com-remove-option) ((option 'class-option :gesture :describe)) (setf (options *application-frame*) (remove option (options *application-frame*))))
(define-class-definer-command (com-change-option) ((option 'class-option :gesture :select)) (with-interaction () (setf (options *application-frame*) (substitute (accept 'class-option :default option) option (options *application-frame*)))))
(defun display-class-definition (*application-frame* *standard-output*) (with-look-and-feel-realization (*default-frame-manager* *application-frame*) (let ((interacting (eql (frame-current-layout *application-frame*) 'interacting))) (macrolet ((labelling ((&key label (newline-p t)) &body body) `(surrounding-output-with-border (t) (with-text-face (t :bold) (princ ,label)) (write-char #:) ,(if newline-p `(terpri) `(write-char #\space)) ,@body))) (labelling (:label "Class Name" :newline-p nil) (princ (name *application-frame*))) (terpri) (labelling (:label "Superclasses") (filling-output (t) (dolist (super (direct-superclasses *application-frame*)) (with-output-as-presentation (t super 'superclass) (princ super)) (write-char #\Space))) (fresh-line) (with-output-as-gadget (t) (make-pane 'push-button :label "Add" :id 'add-superclass :activate-callback #'add-superclass :active-p (not interacting)))) (terpri) (labelling (:label "Slots") (dolist (spec (direct-slots *application-frame*)) (present spec 'slot-specification :single-box t) (terpri)) (with-output-as-gadget (t) (make-pane 'push-button :label "Add" :id 'add-slot :activate-callback #'add-slot :active-p (not interacting)))) (terpri) (labelling (:label "Options") (dolist (option (options *application-frame*)) (present option 'class-option) (terpri))
[4 lines skipped]
rjain-utils-cvs@common-lisp.net