;;; -*- Mode: LISP; Syntax: Common-Lisp; Package: clim-user -*- ;;; ;;; Very simple petri net editor in Common LISP (CLIM/CLOS-Demo) ;;; Lets you create token nets and play with them ;;; Demonstrates some basic CLIM and CLOS programming techniques ;;; (C) 2003 by Michael Wessel ;;; #+(and allegro windows) (require :climnt) (in-package clim-user) ;;; ;;; "Model" Classes ;;; (defclass petri-net () ((places :accessor places :initform nil) (transitions :accessor transitions :initform nil) (edges :accessor edges :initform nil))) (defclass token-net (petri-net) ()) ;;; ;;; ;;; (defclass petri-net-item () ((in-net :accessor in-net :initarg :in-net))) (defclass petri-net-item-with-capacity (petri-net-item) ((capacity :accessor capacity :initarg :capacity :initform 1))) (defclass place-or-transition (petri-net-item) ((outgoing-edges :accessor outgoing-edges :initform nil) (incoming-edges :accessor incoming-edges :initform nil))) ;;; ;;; ;;; (defclass transition (place-or-transition) ()) ;;; ;;; ;;; (defclass place (place-or-transition) ()) (defclass place-with-tokens (place) ((tokens :accessor tokens :initarg :tokens :initform 0))) (defclass place-with-capacity (place-with-tokens petri-net-item-with-capacity) ()) ;;; ;;; ;;; (defclass edge (petri-net-item) ((from :accessor from :initarg :from) (to :accessor to :initarg :to))) (defclass edge-with-capacity (edge petri-net-item-with-capacity) ()) ;;; ;;; ;;; (defun make-petri-net () (make-instance 'petri-net)) (defun make-token-net () (make-instance 'token-net)) ;;; ;;; ;;; (defmethod initialize-instance :after ((transition transition) &rest initargs) (push transition (transitions (in-net transition)))) (defmethod make-transition ((net petri-net) &key &allow-other-keys) (make-instance 'transition :in-net net)) ;;; ;;; ;;; (defmethod initialize-instance :after ((place place) &rest initargs) (push place (places (in-net place)))) (defmethod make-place ((net petri-net) &rest args) (make-instance 'place :in-net net)) (defmethod make-place ((net token-net) &key (tokens 0) capacity &allow-other-keys) (if capacity (make-instance 'place-with-capacity :tokens tokens :capacity capacity :in-net net) (make-instance 'place-with-tokens :tokens tokens :in-net net))) ;;; ;;; ;;; (defmethod initialize-instance :after ((edge edge) &rest initargs) (push edge (outgoing-edges (from edge))) (push edge (incoming-edges (to edge))) (push edge (edges (in-net edge)))) (defmethod link :before ((a place-or-transition) (b place-or-transition) &key &allow-other-keys) (unless (eq (in-net a) (in-net b)) (error "~A and ~A must be in same net!" a b)) (when (some #'(lambda (outgoing-edge) (eq (to outgoing-edge) b)) (outgoing-edges a)) (error "~A and ~A are already linked!" a b))) (defmethod link ((a place-or-transition) (b place-or-transition) &key &allow-other-keys) (error "Can only link places with transitions or transitions with places!")) (defmethod link ((transition transition) (place place) &key &allow-other-keys) (make-instance 'edge :in-net (in-net transition) :from transition :to place)) (defmethod link ((place place) (transition transition) &key &allow-other-keys) (make-instance 'edge :in-net (in-net transition) :from place :to transition)) (defmethod link ((place place-with-tokens) (transition transition) &key (capacity 1) &allow-other-keys) (make-instance 'edge-with-capacity :in-net (in-net transition) :from place :to transition :capacity capacity)) (defmethod link ((transition transition) (place place-with-tokens) &key (capacity 1) &allow-other-keys) (make-instance 'edge-with-capacity :in-net (in-net transition) :from transition :to place :capacity capacity)) ;;; ;;; ;;; (defmethod unlink ((a place-or-transition) (b place-or-transition)) (dolist (outgoing-edge (outgoing-edges a)) (when (eq (to outgoing-edge) b) (remove-from-net outgoing-edge)))) ;;; ;;; ;;; (defmethod remove-from-net ((edge edge)) (setf (outgoing-edges (from edge)) (delete edge (outgoing-edges (from edge)))) (setf (incoming-edges (to edge)) (delete edge (incoming-edges (to edge)))) (setf (edges (in-net edge)) (delete edge (edges (in-net edge)))) (in-net edge)) (defmethod remove-from-net ((place-or-transition place-or-transition)) (dolist (edge (append (outgoing-edges place-or-transition) (incoming-edges place-or-transition))) (remove-from-net edge)) (in-net place-or-transition)) (defmethod remove-from-net :after ((transition transition)) (setf (transitions (in-net transition)) (delete transition (transitions (in-net transition))))) (defmethod remove-from-net :after ((place place)) (setf (places (in-net place)) (delete place (places (in-net place))))) ;;; ;;; ;;; (defmethod may-have-more-tokens-p ((place place-with-tokens)) t) (defmethod may-have-more-tokens-p ((place place-with-capacity)) (< (tokens place) (capacity place))) ;;; ;;; ;;; (defmethod add-tokens ((place place-with-tokens) &optional (tokens 1)) (incf (tokens place) tokens)) (defmethod add-tokens :after ((place place-with-capacity) &optional args) (setf (tokens place) (min (tokens place) (capacity place)))) (defmethod remove-tokens ((place place-with-tokens) &optional (tokens 1)) (unless (zerop (tokens place)) (decf (tokens place) tokens))) ;;; ;;; ;;; (defmethod increase-capacity ((item petri-net-item-with-capacity) &optional (increment 1)) (incf (capacity item) increment)) (defmethod decrease-capacity ((item petri-net-item-with-capacity) &optional (increment 1)) (unless (zerop (1- (capacity item))) (decf (capacity item) increment))) ;;; ;;; ;;; (defmethod activated-p ((transition transition)) (active-p (in-net transition) transition)) (defmethod active-p ((net petri-net) (transition transition)) t) (defmethod active-p ((net token-net) (transition transition)) (and (incoming-edges transition) (every #'(lambda (incoming-edge) (>= (tokens (from incoming-edge)) (capacity incoming-edge))) (incoming-edges transition)) (outgoing-edges transition) (every #'(lambda (outgoing-edge) (or (not (typep (to outgoing-edge) 'place-with-capacity)) (<= (+ (tokens (to outgoing-edge)) (capacity outgoing-edge)) (capacity (to outgoing-edge))))) (outgoing-edges transition)))) ;;; ;;; ;;; (defmethod activate :before ((transition transition)) (unless (activated-p transition) (error "Transition ~A is not active!" transition))) (defmethod activate ((transition transition)) (make-step transition (in-net transition))) ;;; ;;; ;;; (defmethod make-step ((transition transition) (net petri-net)) net) (defmethod make-step ((transition transition) (net token-net)) (dolist (incoming-edge (incoming-edges transition)) (remove-tokens (from incoming-edge) (capacity incoming-edge))) (dolist (outgoing-edge (outgoing-edges transition)) (add-tokens (to outgoing-edge) (capacity outgoing-edge))) net) ;;; ;;; ;;; (defmethod step-net ((net petri-net)) t) (defmethod step-net ((net token-net)) (let ((active-transitions (remove-if-not #'activated-p (transitions net)))) (labels ((one-of (sequence) (elt sequence (random (length sequence))))) (when active-transitions (activate (one-of active-transitions)))))) ;;; ;;; "View" Classes ;;; (defconstant +font+ (make-text-style :sans-serif :bold :very-large)) (defclass display-object () ((color :accessor color :initform +black+))) (defclass positioned-display-object (display-object) ((x :accessor x :initarg :x) (y :accessor y :initarg :y))) (defclass transition-view (positioned-display-object transition) ((color :initform +red+))) (defclass place-view (positioned-display-object place) ((color :initform +blue+))) (defclass place-with-tokens-view (place-view place-with-tokens) ((color :initform +blue+))) (defclass place-with-capacity-view (place-with-tokens-view place-with-capacity) ()) (defclass edge-view (display-object edge) ()) (defclass edge-with-capacity-view (edge-view edge-with-capacity) ()) ;;; ;;; ;;; (defclass petri-net-view (petri-net standard-application-frame) ()) (defclass token-net-view (petri-net-view token-net) ()) ;;; ;;; Solve the "make isn't generic"-problem (kind of "Factory Pattern") ;;; (defmethod make-place ((net petri-net-view) &rest initargs) (apply #'change-class-of-instance (call-next-method) initargs)) (defmethod make-transition ((net petri-net-view) &rest initargs) (apply #'change-class-of-instance (call-next-method) initargs)) (defmethod link :around ((transition transition-view) (place place-view) &rest initargs) (apply #'change-class-of-instance (call-next-method) initargs)) (defmethod link :around ((place place-view) (transition transition-view) &rest initargs) (apply #'change-class-of-instance (call-next-method) initargs)) ;;; ;;; ;;; (defmethod change-class-of-instance ((transition transition) &rest initargs) (apply #'change-class transition 'transition-view initargs)) (defmethod change-class-of-instance ((place place) &rest initargs) (apply #'change-class place 'place-view initargs)) (defmethod change-class-of-instance ((place place-with-tokens) &rest initargs) (apply #'change-class place 'place-with-tokens-view initargs)) (defmethod change-class-of-instance ((place place-with-capacity) &rest initargs) (apply #'change-class place 'place-with-capacity-view initargs)) (defmethod change-class-of-instance ((edge edge) &rest initargs) (apply #'change-class edge 'edge-view initargs)) (defmethod change-class-of-instance ((edge edge-with-capacity) &rest initargs) (apply #'change-class edge 'edge-with-capacity-view initargs)) ;;; ;;; ;;; (defun get-random-net (n m p) (let ((net (make-petri-net))) (change-class net 'petri-net-view) (let ((places (loop as i from 1 to n collect (make-place net))) (transitions (loop as i from 1 to m collect (make-transition net)))) (loop as place in places do (loop as transition in transitions do (when (zerop (random p)) (link place transition))))) net)) ;;; ;;; Define the application frame ;;; Use inheritance to get a petri net editor ;;; (instead of, e.g., using association) ;;; (define-application-frame petri-net-editor (token-net-view) (; (net :accessor net :initform (get-random-net 10 10 3)) (scaling-factor :accessor scaling-factor :initform 1.0)) (:command-table (petri-net-editor :menu (("Commands" :menu command-table)))) (:panes (pointer-documentation-pane (make-clim-stream-pane :type 'pointer-documentation-pane :text-style +font+ :height '(1 :line) :min-height '(1 :line) :max-height '(1 :line))) (command :interactor :text-style +font+) (display :application :height 400 :display-function #'draw :incremental-redisplay t :redisplay-after-commands t :scroll-bars :both) (scaling-factor :application :scroll-bars nil :height '(1 :line) :min-height '(1 :line) :max-height '(1 :line) :text-style +font+ :incremental-redisplay t :display-function #'(lambda (frame stream) (updating-output (stream :unique-id 'scaling-factor :cache-value (scaling-factor frame) :cache-test #'=) (format stream "Current Scaling Factor: ~A" (scaling-factor frame))))) (slider (make-pane 'slider :client 'slider :text-style +font+ :id 'slider :min-value 0.1 :max-value 10 :number-of-tick-marks 10 :value-changed-callback #'(lambda (slider val) (declare (ignore slider)) (with-application-frame (frame) (setf (scaling-factor frame) val) (redisplay-frame-panes frame))))) (quit-button (make-pane 'push-button :label "Quit!" :text-style +font+ :activate-callback #'(lambda (button) (declare (ignore button)) (with-application-frame (frame) (frame-exit frame))))) (refresh-button (make-pane 'push-button :label "Refresh!" :text-style +font+ :activate-callback #'(lambda (button) (declare (ignore button)) (with-application-frame (frame) (setf (scaling-factor frame) 1.0) (redisplay-frame-panes frame :force-p t))))) (step-button (make-pane 'push-button :label "Step!" :text-style +font+ :activate-callback #'(lambda (button) (declare (ignore button)) (with-application-frame (frame) (step-net frame) (redisplay-frame-panes frame)))))) (:layouts (:default (vertically () #+:lispworks display #+:lispworks (horizontally () (1/7 quit-button) (1/7 refresh-button) (1/7 step-button) (4/7 (vertically () (1/2 scaling-factor) (1/2 slider)))) #-:lispworks (500 display) #-:lispworks (90 (horizontally () (1/7 quit-button) (1/7 refresh-button) (1/7 step-button) (4/7 (vertically () (1/2 scaling-factor) (1/2 slider))))) command pointer-documentation-pane)))) ;;; ;;; ;;; (defmethod get-pane-size ((stream stream)) (bounding-rectangle-size (bounding-rectangle (window-viewport stream)))) (defmethod get-relative-coordinates ((frame petri-net-editor) x y) (multiple-value-bind (width height) (get-pane-size (get-frame-pane frame 'display)) (values (/ (/ x width) (scaling-factor frame)) (/ (/ y height) (scaling-factor frame))))) (defmethod get-dimensions ((transition transition-view)) (with-application-frame (frame) (values (/ 0.05 (scaling-factor frame)) (/ 0.03 (scaling-factor frame))))) (defmethod get-dimensions ((place place-view)) (with-application-frame (frame) (values (/ 0.05 (scaling-factor frame))))) ;;; ;;; Draw the editor's content ;;; (defmethod draw ((frame petri-net-editor) stream) (multiple-value-bind (width height) (get-pane-size stream) (with-scaling (stream (scaling-factor frame) (scaling-factor frame) ) (with-scaling (stream width height) (dolist (object (append (places frame) (transitions frame))) (present object (type-of object) :stream stream :view +gadget-view+ :single-box t)) (dolist (edge (edges frame)) (present edge (type-of edge) :stream stream :view +gadget-view+)))))) ;;; ;;; Define the presentation methods ;;; (define-presentation-method present :around (object (type positioned-display-object) stream (view gadget-view) &key) (with-translation (stream (x object) (y object)) (call-next-method))) (define-presentation-method present :around (object (type display-object) stream (view gadget-view) &key) (with-drawing-options (stream :line-thickness 3 :ink (color object) :text-style +font+) (call-next-method))) (define-presentation-method present (place (type place-view) stream (view gadget-view) &key) (with-application-frame (frame) (multiple-value-bind (radius) (get-dimensions place) (updating-output (stream :unique-id place :cache-value (list (scaling-factor frame) (x place) (y place) (color place)) :cache-test #'equal) (draw-circle* stream 0 0 radius :filled nil))))) (define-presentation-method present (place (type place-with-tokens-view) stream (view gadget-view) &key) (with-application-frame (frame) (labels ((deg-to-rad (phi) (* pi (/ phi 180)))) (multiple-value-bind (radius) (get-dimensions place) (updating-output (stream :unique-id place :cache-value (list (scaling-factor frame) (x place) (y place) (color place) (tokens place)) :cache-test #'equal) (draw-circle* stream 0 0 radius :filled nil)) (unless (zerop (tokens place)) (let* ((n (tokens place)) (w (/ 360 n)) (r (* 2/3 radius)) (s (* 1/8 radius))) (loop as a from 1 to n do (draw-circle* stream (* r (sin (deg-to-rad (* a w)))) (* r (cos (deg-to-rad (* a w)))) s :ink +black+)))))))) (define-presentation-type capacity-label-view ()) (define-presentation-method presentation-typep (object (type capacity-label-view)) (typep object 'petri-net-item-with-capacity)) (define-presentation-method present :after (place (type place-with-capacity-view) stream (view gadget-view) &key) (with-application-frame (frame) (multiple-value-bind (radius) (get-dimensions place) (updating-output (stream :unique-id (list place (capacity place)) :id-test #'equal :cache-value (list (scaling-factor frame) (x place) (x place) (color place) (capacity place)) :cache-test #'equal) (with-output-as-presentation (stream place 'capacity-label-view) (draw-text* stream (format nil "~A" (capacity place)) radius radius)))))) (define-presentation-method present (transition (type transition-view) stream (view gadget-view) &key) (with-application-frame (frame) (multiple-value-bind (width height) (get-dimensions transition) (updating-output (stream :unique-id transition :cache-value (list (activated-p transition) (scaling-factor frame) (x transition) (x transition) (color transition)) :cache-test #'equal) (draw-rectangle* stream (- width) (- height) width height :filled (activated-p transition)))))) (define-presentation-method present (edge (type edge-view) stream (view gadget-view) &key) (with-application-frame (frame) (let ((from (from edge)) (to (to edge))) (updating-output (stream :unique-id edge :cache-value (list (scaling-factor frame) (x from) (x to) (y from) (y to) (color edge)) :cache-test #'equal) (draw-arrow* stream (x from) (y from) (x to) (y to) :line-thickness 2 :head-length (/ 0.03 (scaling-factor frame)) :head-width (/ 0.03 (scaling-factor frame))))))) (define-presentation-method present :after (edge (type edge-with-capacity-view) stream (view gadget-view) &key) (with-application-frame (frame) (let ((from (from edge)) (to (to edge))) (updating-output (stream :unique-id (list edge (capacity edge)) :id-test #'equal :cache-value (list (scaling-factor frame) (x from) (x to) (y from) (y to) (color edge) (capacity edge)) :cache-test #'equal) (with-output-as-presentation (stream edge 'capacity-label-view) (draw-text* stream (format nil "~A" (capacity edge)) (/ (+ (x from) (x to)) 2) (/ (+ (y from) (y to)) 2))))))) ;;; ;;; Define some gesture names ;;; (define-gesture-name :new-place :pointer-button :left) (define-gesture-name :new-transition :pointer-button (:left :shift)) (define-gesture-name :delete :pointer-button :left) (define-gesture-name :activate :pointer-button (:right :shift)) (define-gesture-name :move :pointer-button (:control :left)) (define-gesture-name :add-token :pointer-button :middle) (define-gesture-name :remove-token :pointer-button (:middle :shift)) (define-gesture-name :add-capacity-label :pointer-button (:middle :control)) ;;; ;;; Define some editor commands ;;; (define-petri-net-editor-command (com-new-transition :menu nil :name "New Transition") ((x 'integer) (y 'integer)) (with-application-frame (frame) (multiple-value-bind (x y) (get-relative-coordinates frame x y) (make-transition frame :x x :y y)))) (define-petri-net-editor-command (com-new-place :menu nil :name nil) ((x 'integer) (y 'integer)) (with-application-frame (frame) (multiple-value-bind (x y) (get-relative-coordinates frame x y) (make-place frame :x x :y y)))) ;;; ;;; (define-petri-net-editor-command (com-link-place-with-transition :menu nil :name "Link Place with Transition") ((place 'place-view) (transition 'transition-view)) (link place transition)) (define-petri-net-editor-command (com-link-transition-with-place :menu nil :name "Link Transition with Place") ((transition 'transition-view) (place 'place-view)) (link transition place)) ;;; ;;; ;;; (define-petri-net-editor-command (com-unlink-place-and-transition :menu nil :name "Unlink Place and Transition") ((place 'place-view) (transition 'transition-view)) (unlink place transition)) (define-petri-net-editor-command (com-unlink-transition-and-place :menu nil :name "Unlink Transition and Place") ((transition 'transition-view) (place 'place-view)) (unlink transition place)) ;;; ;;; ;;; (define-petri-net-editor-command (com-delete-object :menu nil :name "Delete Object") ((object 'display-object)) (remove-from-net object)) ;;; ;;; ;;; ;;; (define-petri-net-editor-command (com-add-token :menu nil :name "Add Token") ((place-with-tokens `(and place-with-tokens-view (satisfies may-have-more-tokens-p)))) (add-tokens place-with-tokens)) (define-petri-net-editor-command (com-remove-token :menu nil :name "Remove Token") ((place-with-tokens `(and place-with-tokens-view (satisfies ,#'(lambda (place) (not (zerop (tokens place)))))))) (remove-tokens place-with-tokens)) ;;; ;;; ;;; (define-petri-net-editor-command (com-add-capacity-label :menu nil :name "Add Capacity Label") ((place-with-tokens `(and place-with-tokens-view (satisfies ,#'(lambda (object) (not (typep object 'place-with-capacity-view)))))) (capacity 'integer)) (apply #'change-class place-with-tokens 'place-with-capacity-view :capacity capacity nil)) ;;; ;;; ;;; (define-petri-net-editor-command (com-increase-capacity :menu nil :name "Increase Capacity") ((capacity-label 'capacity-label-view)) (increase-capacity capacity-label 1)) (define-petri-net-editor-command (com-decrease-capacity :menu nil :name "Decrease Capacity") ((capacity-label `(and capacity-label-view (satisfies ,#'(lambda (object) (not (zerop (1- (capacity object))))))))) (decrease-capacity capacity-label 1)) ;;; ;;; ;;; (define-petri-net-editor-command (com-activate-transition :menu nil :name "Activate Transition") ((transition 'transition-view)) (activate transition)) ;;; ;;; ;;; (define-petri-net-editor-command (com-move-display-object :menu nil :name "Move Display Object") ((object 'positioned-display-object)) (with-application-frame (frame) (let ((ox (x object)) (oy (y object)) (stream (get-frame-pane frame 'display))) (tracking-pointer (stream) (:pointer-motion (x y) (multiple-value-bind (x y) (get-relative-coordinates frame x y) (setf (x object) x (y object) y) (redisplay-frame-pane frame stream))) (:pointer-button-press (event) (when (= (pointer-event-button event) +pointer-right-button+) (setf (x object) ox (y object) oy)) (return)))))) (define-petri-net-editor-command (com-new-transition-no-arguments :menu nil :name "New Transition") nil (with-application-frame (frame) (let ((stream (get-frame-pane frame 'display))) (multiple-value-bind (x y) (tracking-pointer (stream) (:pointer-button-press (x y event) (when (= (pointer-event-button event) +pointer-left-button+) (return (values x y))))) (com-new-transition x y))))) (define-petri-net-editor-command (com-new-place-no-arguments :menu nil :name "New Place") nil (with-application-frame (frame) (let ((stream (get-frame-pane frame 'display))) (multiple-value-bind (x y) (tracking-pointer (stream) (:pointer-button-press (x y event) (when (= (pointer-event-button event) +pointer-left-button+) (return (values x y))))) (com-new-place x y))))) ;;; ;;; Define some presentation translators ;;; (define-presentation-to-command-translator move-display-object (positioned-display-object com-move-display-object petri-net-editor :gesture :move :documentation ((stream) (format stream "Move This Object")) :echo t :maintain-history nil) (object) (list object)) (define-presentation-to-command-translator delete-object (display-object com-delete-object petri-net-editor :gesture :delete :documentation ((stream) (format stream "Delete This Object")) :echo nil :maintain-history nil) (object) (list object)) (define-presentation-to-command-translator new-transition (blank-area com-new-transition petri-net-editor :gesture :new-transition :documentation ((stream) (format stream "Create New Transition")) :echo nil :maintain-history nil) (x y) (list x y)) (define-presentation-to-command-translator new-place (blank-area com-new-place petri-net-editor :gesture :new-place :documentation ((stream) (format stream "Create New Place")) :echo nil :maintain-history nil) (x y) (list x y)) (define-presentation-to-command-translator add-token (place-with-tokens-view com-add-token petri-net-editor :gesture :add-token :tester ((object) (may-have-more-tokens-p object)) :documentation ((stream) (format stream "Add a Token")) :echo t :maintain-history nil) (object) (list object)) (define-presentation-to-command-translator remove-token (place-with-tokens-view com-remove-token petri-net-editor :gesture :remove-token :tester ((object) (not (zerop (tokens object)))) :documentation ((stream) (format stream "Remove a Token")) :echo t :maintain-history nil) (object) (list object)) (define-presentation-to-command-translator add-capacity-label (place-with-tokens-view com-add-capacity-label petri-net-editor :gesture :add-capacity-label :tester ((object) (not (typep object 'place-with-capacity-view))) :documentation ((stream) (format stream "Add a Capacity Label")) :echo t :maintain-history nil) (object) (list object 4)) (define-presentation-to-command-translator increase-capacity (capacity-label-view com-increase-capacity petri-net-editor :gesture :add-token :documentation ((stream) (format stream "Increase Capacity")) :echo t :maintain-history t) (object) (list object)) (define-presentation-to-command-translator decrease-capacity (capacity-label-view com-decrease-capacity petri-net-editor :gesture :remove-token :tester ((object) (not (zerop (1- (capacity object))))) :documentation ((stream) (format stream "Decrease Capacity")) :echo t :maintain-history nil) (object) (list object)) (define-presentation-to-command-translator activate-transition (transition-view com-activate-transition petri-net-editor :gesture :activate :tester ((object) (activated-p object)) :documentation ((stream) (format stream "Activate Transition")) :echo t :maintain-history nil) (object) (list object)) ;;; ;;; Define the command table ;;; (define-command-table command-table :menu (("New Transition" :command (com-new-transition-no-arguments)) ("New Place" :command (com-new-place-no-arguments)) ("Link Place with Transtion" :command (com-link-place-with-transition)) ("Link Transtion with Place" :command (com-link-transition-with-place)) ("divide1" :divider nil) ("Delete Object" :command (com-delete-object)) ("divide2" :divider nil) ("Add Capacity Label" :command (com-add-capacity-label)) ("Increase Capacity" :command (com-increase-capacity)) ("Decrease Capacity" :command (com-decrease-capacity)) ("divide3" :divider nil) ("Add Token" :command (com-add-token)) ("Remove Toke" :command (com-remove-token)) ("divide4" :divider nil) ("Activate Transition" :command (com-activate-transition)))) ;;; ;;; Run the application ;;; (defun petri () (setf *application-frame* (make-application-frame 'petri-net-editor :width 700 :height 800)) (run-frame-top-level *application-frame*)) (petri)