Commit 56cb6971 authored by David O'Toole's avatar David O'Toole

fix dialog centering and other issues

parent cfbe3075
;; Captions and labels
;; [[file:~/quicklisp/local-projects/xelf/gui.org::*Captions%20and%20labels][Captions and labels:1]]
;; [[file:~/xelf/gui.org::*Captions%20and%20labels][Captions and labels:1]]
(in-package :xelf)
(defmethod set-caption-string ((self node) caption)
......@@ -40,7 +40,7 @@
;; Shell operations
;; [[file:~/quicklisp/local-projects/xelf/gui.org::*Shell%20operations][Shell operations:1]]
;; [[file:~/xelf/gui.org::*Shell%20operations][Shell operations:1]]
(defmethod drag ((self shell) x y)
(with-slots (target-x target-y) self
(setf target-x (- x (window-x)))
......@@ -186,7 +186,7 @@
;; Automatic layout
;; [[file:~/quicklisp/local-projects/xelf/gui.org::*Automatic%20layout][Automatic layout:1]]
;; [[file:~/xelf/gui.org::*Automatic%20layout][Automatic layout:1]]
(defmethod update :after ((self shell))
(layout self)
(mapc #'layout (%inputs self))
......@@ -199,7 +199,7 @@
;; Dialog box builder
;; [[file:~/quicklisp/local-projects/xelf/gui.org::*Dialog%20box%20builder][Dialog box builder:1]]
;; [[file:~/xelf/gui.org::*Dialog%20box%20builder][Dialog box builder:1]]
(defclass dialog (phrase)
((orientation :initform :vertical)
(no-background :initform nil)
......@@ -215,7 +215,11 @@
(draw-patch self x y (+ x width) (+ y height) :color color :style :rounded)))
(defmethod tap ((dialog dialog) x y)
(bring-to-front (or (parent dialog) dialog)))
(bring-to-front (or (parent dialog) dialog))
(tap (or (parent dialog) dialog) x y))
(defmethod freeze :after ((dialog dialog))
(mapc #'freeze (inputs dialog)))
(defmacro define-dialog (name arglist &body body)
`(progn
......@@ -354,7 +358,7 @@
;; System object
;; [[file:~/quicklisp/local-projects/xelf/gui.org::*System%20object][System object:1]]
;; [[file:~/xelf/gui.org::*System%20object][System object:1]]
(defvar *system* nil)
(defclass system (node)
......@@ -372,10 +376,12 @@
(defun show-dialog (dialog title &key destroy-after-evaluate-p)
(let ((frame (make-frame title dialog :destroy-after-evaluate-p destroy-after-evaluate-p)))
(add-node (current-buffer) frame)
(layout dialog)
(layout frame)
(center frame)
(align-to-pixels frame)
(freeze dialog)
(mapc #'freeze (inputs dialog))
(close-menus *menubar*)
nil))
(defun do-cut ()
......@@ -423,9 +429,6 @@
(defun save-everything ()
(save-project :force))
(defun initialize ()
(setf *system* self))
(defun create-trash ()
(add-block (shell) (make-instance 'trash) 100 100))
......@@ -446,7 +449,7 @@
;; User dialogs
;; [[file:~/quicklisp/local-projects/xelf/gui.org::*User%20dialogs][User dialogs:1]]
;; [[file:~/xelf/gui.org::*User%20dialogs][User dialogs:1]]
;; (define-dialog rename-buffer
;; ((new-name (slot-value (current-buffer) 'buffer-name)))
;; (rename-buffer (current-buffer) new-name))
......@@ -459,20 +462,21 @@
(define-dialog visit-buffer
((buffer-name (or (first *buffer-history*)
(buffer-name (current-buffer)))))
(switch-to-buffer buffer-name))
(at-next-update (switch-to-buffer buffer-name)))
(define-dialog create-buffer
((buffer-name (uniquify-buffer-name "*untitled-buffer*"))
(buffer-class 'buffer))
((buffer-name (uniquify-buffer-name "*untitled*"))
(buffer-class (class-name (class-of (current-buffer)))))
(at-next-update
(switch-to-buffer (make-instance buffer-class :buffer-name buffer-name))))
(define-dialog paste-as-new-buffer
((buffer-name (uniquify-buffer-name "*pasted-buffer*"))
(buffer-class (class-name (class-of (current-buffer))))
(offset-x 0)
(offset-y 0))
(at-next-update
(let ((buffer (make-instance 'buffer :buffer-name buffer-name)))
(let ((buffer (make-instance buffer-class :buffer-name buffer-name)))
(switch-to-buffer buffer-name)
(paste (current-buffer) offset-x offset-y)
(trim-conservatively (current-buffer)))))
......@@ -499,16 +503,31 @@
(setf *title* title)
(setf *author* author)
(setf *author-contact* author)
(setf *width* width)
(setf *height* height)
(setf *screen-width* width)
(setf *screen-height* height)
(setf *resizable* resizable))
(notify (format nil "Applied project properties to ~S." project)))
(defun all-buffer-names ()
(loop for name being the hash-keys of *buffers* collect name))
(defclass buffer-list (text) ())
(defmethod tap :after ((buffer-list buffer-list) x y)
(with-slots (point-row) buffer-list
(at-next-update (switch-to-buffer (nth point-row (slot-value buffer-list 'buffer))))))
(defclass buffer-list-dialog (dialog)
((inputs :initform (list (make-instance 'buffer-list :text (all-buffer-names))))))
(defun show-buffer-list-dialog ()
(show-dialog (make-instance 'buffer-list-dialog) "Buffer list" :destroy-after-evaluate-p t))
;; User dialogs:1 ends here
;; Menu bar structure
;; [[file:~/quicklisp/local-projects/xelf/gui.org::*Menu%20bar%20structure][Menu bar structure:1]]
;; [[file:~/xelf/gui.org::*Menu%20bar%20structure][Menu bar structure:1]]
(defparameter *project-menu*
'(:label "Project"
:inputs
......@@ -564,10 +583,15 @@
(:label "Destroy buffer" :action show-destroy-buffer-dialog)
(:label "Save buffer in new file" :action show-save-buffer-in-new-file-dialog)
(:label "Revert buffer" :action show-revert-buffer-dialog)
(:label "Resize to background image" :action resize-to-background-image)
(:label "Resize to background image" :action do-resize-to-background-image)
(:label "Make snapshot" :action show-take-snapshot-dialog)
(:label "View clipboard" :action view-clipboard)
(:label "View buffer list" :action view-buffer-list))))
(:label "View buffer list" :action show-buffer-list-dialog))))
(defun do-resize-to-background-image ()
(if (background-image (current-buffer))
(resize-to-background-image (current-buffer))
(notify "No background image to resize to.")))
(defun do-show-buffer-properties-dialog ()
(show-buffer-properties-dialog (current-buffer)))
......@@ -672,7 +696,7 @@
;; Traveling nodes
;; [[file:~/quicklisp/local-projects/xelf/gui.org::*Traveling%20nodes][Traveling nodes:1]]
;; [[file:~/xelf/gui.org::*Traveling%20nodes][Traveling nodes:1]]
(defclass traveler (node)
((parent-buffer :initform nil)))
......@@ -688,7 +712,7 @@
;; Menubar class
;; [[file:~/quicklisp/local-projects/xelf/gui.org::*Menubar%20class][Menubar class:1]]
;; [[file:~/xelf/gui.org::*Menubar%20class][Menubar class:1]]
(defclass menubar (tree traveler)
((category :initform :menu)
(temporary :initform t)))
......@@ -788,7 +812,8 @@
(defmethod tap ((self menubar) x y)
(let ((target (hit self x y)))
(show-status (format nil "Hitting target ~S" target))
(when (not (object-eq target self))
(when (and (xelfp target)
(not (object-eq target self)))
(tap target x y))
(close-menus self)))
......@@ -804,7 +829,7 @@
;; Floating window frames
;; [[file:~/quicklisp/local-projects/xelf/gui.org::*Floating%20window%20frames][Floating window frames:1]]
;; [[file:~/xelf/gui.org::*Floating%20window%20frames][Floating window frames:1]]
(define-handle frame-close-button :close
:slots ((target-frame :initform nil :initarg :target-frame :accessor target-frame)))
......@@ -815,7 +840,12 @@
(defmethod layout ((self frame-close-button))
(resize self 20 20))
(defclass titlebar-label (label) ())
(defmethod tap ((self titlebar-label) x y)
(let ((it (parent (parent self))))
(when it
(tap it x y))))
(define-visual-macro titlebar
(:super phrase
......@@ -826,16 +856,11 @@
(dash :initform 1)
(category :initform :system))
:inputs (:close-button (make-instance 'frame-close-button)
:title (make-instance 'label :font "sans-bold-11" :read-only t :locked t))))
:title (make-instance 'titlebar-label :font "sans-bold-11" :read-only t :locked t))))
(defmethod set-title ((self titlebar) title)
(set-value (input-node self :title) title))
(defmethod tap ((self titlebar) x y)
(let ((it (parent (parent self))))
(when it
(tap it x y))))
(define-visual-macro frame
(:super phrase
:slots ((frozen :initform t)
......@@ -895,7 +920,7 @@
;; Context menus
;; [[file:~/quicklisp/local-projects/xelf/gui.org::*Context%20menus][Context menus:1]]
;; [[file:~/xelf/gui.org::*Context%20menus][Context menus:1]]
(defmethod make-method-menu-item ((self node) method target)
(assert (and target method (symbolp method)))
(let ((method-string (pretty-string method)))
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This diff is collapsed.
......@@ -652,7 +652,7 @@ This section is obsolete and will be removed in the future.
(setf (slot-value self 'point) (find-uuid point)))
#+end_src
** TODO Drawing the buffer
** Drawing the buffer
#+begin_src lisp
(defmethod grab-focus ((self buffer)))
......@@ -750,9 +750,6 @@ This section is obsolete and will be removed in the future.
(find-bounding-box objects)
(resize self right bottom))))))
#+end_src
** Copy, cut, and paste
#+begin_src lisp
......@@ -1541,8 +1538,7 @@ above.
(:escape nil exit)))
(defparameter *arrow-key-text-navigation-keybindings*
'(
(:up nil previous-line)
'((:up nil previous-line)
(:down nil next-line)
(:left nil backward-char)
(:right nil forward-char)
......@@ -1653,7 +1649,7 @@ above.
(defmethod pick-focus ((self node)) self)
#+end_src
* TODO Halos
* Halos
#+begin_src lisp
(defparameter *handle-scale* 3.2)
......@@ -2843,13 +2839,12 @@ hybrid GUI inspired by MIT Scratch and its derivatives.
;;; Layout management
(defmethod center ((self node))
"Automatically center the node on the screen."
(with-slots (window-x window-y) *buffer*
(with-slots (window-x window-y) (current-buffer)
(with-slots (x y width height) self
(let ((center-x (+ window-x (/ *screen-width* 2)))
(center-y (+ window-y (/ *screen-height* 2))))
(setf x (+ (- center-x (/ width 2))))
(setf y (+ (- center-y (/ width 2))))))))
(setf y (+ (- center-y (/ height 2))))))))
(defmethod center-as-dialog ((self node))
(layout self)
......@@ -2994,10 +2989,11 @@ supported compiler.
(orientation :initform :vertical)
(operation :initform :empty-phrase)
(result :initform nil)
(collision-type :initform nil)
(category :initform :structure)))
(defmethod update :after ((self phrase))
(layout self))
(layout self))
(defmethod evaluate ((self phrase))
(mapcar #'evaluate (slot-value self 'inputs)))
......@@ -3573,6 +3569,31 @@ supported compiler.
(auto-fit :initform t)
(visible :initform t)))
(defmethod tap ((self text) x y)
(with-slots (buffer width parent height) self
(with-slots (x y font point-row point-column indicator) self
(with-slots (x y clock point parent background) self
;; find the left edge of the text
(let* ((left (+ x *text-margin*))
(tx (- x left))
(ty (- y (slot-value self 'y)))
;; which row was clicked?
(row (truncate (/ (+ *text-margin* ty) (font-height font))))
(line (nth row buffer)))
;; move to correct row
(setf point-row row)
;; which character was clicked?
(let ((click-index
(block measuring
(dotimes (ix (length line))
(when (< tx (font-text-width
(subseq line 0 ix)
*font*))
(return-from measuring ix))))))
;; move to correct column
(when (numberp click-index)
(setf point-column click-index))))))))
(defmethod get-first-line ((self text))
(or (first (slot-value self 'buffer))
"Notification text not found."))
......@@ -3678,9 +3699,11 @@ supported compiler.
(setf (slot-value self 'buffer) text))
;; (when (and buffer (listp buffer) (every #'stringp buffer))
;; (setf (slot-value self 'buffer) buffer))
(layout self))
;; (install-text-keybindings self)
;; (install-keybindings self *arrow-key-text-navigation-keybindings*))))
(layout self)
(install-text-keybindings
self
(append *text-qwerty-keybindings*
*arrow-key-text-navigation-keybindings*)))
(defmethod forward-char ((self text))
(with-slots (buffer point-row point-column) self
......@@ -4227,7 +4250,6 @@ supported compiler.
(symbol
(when (fboundp action)
(funcall (symbol-function action)))))
;;(or target (symbol-value '*system*))))))
(progn
;; we're a submenu, not an individual menu command.
;; first close any other open menus
......@@ -4783,7 +4805,11 @@ supported compiler.
(draw-patch self x y (+ x width) (+ y height) :color color :style :rounded)))
(defmethod tap ((dialog dialog) x y)
(bring-to-front (or (parent dialog) dialog)))
(bring-to-front (or (parent dialog) dialog))
(tap (or (parent dialog) dialog) x y))
(defmethod freeze :after ((dialog dialog))
(mapc #'freeze (inputs dialog)))
(defmacro define-dialog (name arglist &body body)
`(progn
......@@ -4939,10 +4965,12 @@ supported compiler.
(defun show-dialog (dialog title &key destroy-after-evaluate-p)
(let ((frame (make-frame title dialog :destroy-after-evaluate-p destroy-after-evaluate-p)))
(add-node (current-buffer) frame)
(layout dialog)
(layout frame)
(center frame)
(align-to-pixels frame)
(freeze dialog)
(mapc #'freeze (inputs dialog))
(close-menus *menubar*)
nil))
(defun do-cut ()
......@@ -4990,9 +5018,6 @@ supported compiler.
(defun save-everything ()
(save-project :force))
(defun initialize ()
(setf *system* self))
(defun create-trash ()
(add-block (shell) (make-instance 'trash) 100 100))
......@@ -5025,20 +5050,21 @@ supported compiler.
(define-dialog visit-buffer
((buffer-name (or (first *buffer-history*)
(buffer-name (current-buffer)))))
(switch-to-buffer buffer-name))
(at-next-update (switch-to-buffer buffer-name)))
(define-dialog create-buffer
((buffer-name (uniquify-buffer-name "*untitled-buffer*"))
(buffer-class 'buffer))
((buffer-name (uniquify-buffer-name "*untitled*"))
(buffer-class (class-name (class-of (current-buffer)))))
(at-next-update
(switch-to-buffer (make-instance buffer-class :buffer-name buffer-name))))
(define-dialog paste-as-new-buffer
((buffer-name (uniquify-buffer-name "*pasted-buffer*"))
(buffer-class (class-name (class-of (current-buffer))))
(offset-x 0)
(offset-y 0))
(at-next-update
(let ((buffer (make-instance 'buffer :buffer-name buffer-name)))
(let ((buffer (make-instance buffer-class :buffer-name buffer-name)))
(switch-to-buffer buffer-name)
(paste (current-buffer) offset-x offset-y)
(trim-conservatively (current-buffer)))))
......@@ -5069,6 +5095,21 @@ supported compiler.
(setf *screen-height* height)
(setf *resizable* resizable))
(notify (format nil "Applied project properties to ~S." project)))
(defun all-buffer-names ()
(loop for name being the hash-keys of *buffers* collect name))
(defclass buffer-list (text) ())
(defmethod tap :after ((buffer-list buffer-list) x y)
(with-slots (point-row) buffer-list
(at-next-update (switch-to-buffer (nth point-row (slot-value buffer-list 'buffer))))))
(defclass buffer-list-dialog (dialog)
((inputs :initform (list (make-instance 'buffer-list :text (all-buffer-names))))))
(defun show-buffer-list-dialog ()
(show-dialog (make-instance 'buffer-list-dialog) "Buffer list" :destroy-after-evaluate-p t))
#+end_src
** Menu bar structure
......@@ -5129,10 +5170,15 @@ supported compiler.
(:label "Destroy buffer" :action show-destroy-buffer-dialog)
(:label "Save buffer in new file" :action show-save-buffer-in-new-file-dialog)
(:label "Revert buffer" :action show-revert-buffer-dialog)
(:label "Resize to background image" :action resize-to-background-image)
(:label "Resize to background image" :action do-resize-to-background-image)
(:label "Make snapshot" :action show-take-snapshot-dialog)
(:label "View clipboard" :action view-clipboard)
(:label "View buffer list" :action view-buffer-list))))
(:label "View buffer list" :action show-buffer-list-dialog))))
(defun do-resize-to-background-image ()
(if (background-image (current-buffer))
(resize-to-background-image (current-buffer))
(notify "No background image to resize to.")))
(defun do-show-buffer-properties-dialog ()
(show-buffer-properties-dialog (current-buffer)))
......@@ -5353,7 +5399,8 @@ supported compiler.
(defmethod tap ((self menubar) x y)
(let ((target (hit self x y)))
(show-status (format nil "Hitting target ~S" target))
(when (not (object-eq target self))
(when (and (xelfp target)
(not (object-eq target self)))
(tap target x y))
(close-menus self)))
......@@ -5379,7 +5426,12 @@ supported compiler.
(defmethod layout ((self frame-close-button))
(resize self 20 20))
(defclass titlebar-label (label) ())
(defmethod tap ((self titlebar-label) x y)
(let ((it (parent (parent self))))
(when it
(tap it x y))))
(define-visual-macro titlebar
(:super phrase
......@@ -5390,16 +5442,11 @@ supported compiler.
(dash :initform 1)
(category :initform :system))
:inputs (:close-button (make-instance 'frame-close-button)
:title (make-instance 'label :font "sans-bold-11" :read-only t :locked t))))
:title (make-instance 'titlebar-label :font "sans-bold-11" :read-only t :locked t))))
(defmethod set-title ((self titlebar) title)
(set-value (input-node self :title) title))
(defmethod tap ((self titlebar) x y)
(let ((it (parent (parent self))))
(when it
(tap it x y))))
(define-visual-macro frame
(:super phrase
:slots ((frozen :initform t)
......
;; Shell workspace (shell.lisp)
;; [[file:~/quicklisp/local-projects/xelf/gui.org::*Shell%20workspace%20(shell.lisp)][Shell workspace (shell.lisp):1]]
;; [[file:~/xelf/gui.org::*Shell%20workspace%20(shell.lisp)][Shell workspace (shell.lisp):1]]
(in-package :xelf)
;; Shell workspace (shell.lisp):1 ends here
;; Messenger widget
;; [[file:~/quicklisp/local-projects/xelf/gui.org::*Messenger%20widget][Messenger widget:1]]
;; [[file:~/xelf/gui.org::*Messenger%20widget][Messenger widget:1]]
(defclass messenger (node)
((category :initform :terminal)
(messages :initform nil)))
......@@ -64,7 +64,7 @@
;; Modeline
;; [[file:~/quicklisp/local-projects/xelf/gui.org::*Modeline][Modeline:1]]
;; [[file:~/xelf/gui.org::*Modeline][Modeline:1]]
(defvar *modeline-status-string* nil)
(defun show-status (string)
......@@ -125,7 +125,7 @@
;; Interactive dialog box tools
;; [[file:~/quicklisp/local-projects/xelf/gui.org::*Interactive%20dialog%20box%20tools][Interactive dialog box tools:1]]
;; [[file:~/xelf/gui.org::*Interactive%20dialog%20box%20tools][Interactive dialog box tools:1]]
(defun arglist-input-forms (argument-forms)
(mapcar #'(lambda (f)
`(make-sentence
......@@ -164,7 +164,7 @@
;; Shell prompt
;; [[file:~/quicklisp/local-projects/xelf/gui.org::*Shell%20prompt][Shell prompt:1]]
;; [[file:~/xelf/gui.org::*Shell%20prompt][Shell prompt:1]]
(defclass shell-prompt (entry)
((result :initform nil)
(background :initform nil)
......@@ -204,7 +204,7 @@
;; (bind-event self '(:escape) 'close-shell))
;; Shell prompt:1 ends here
;; [[file:~/quicklisp/local-projects/xelf/gui.org::*Shell%20prompt][Shell prompt:2]]
;; [[file:~/xelf/gui.org::*Shell%20prompt][Shell prompt:2]]
(defparameter *minimum-shell-width* 400)
(defparameter *shell-background-color* "gray20")
......
* Task list
** TODO fix dialog boxes
*** DONE [#B] fix *untitled-buffer* not being added to list
CLOSED: [2017-04-22 Sat 07:54]
*** TODO [#A] context-menu with reset-to-current-values
**** TODO pin down context menu elements
**** TODO fix broken layout/rendering of context menu
*** TODO [#A] show error bubble and restore value when input incorrect
*** TODO [#A] fix halos not always being in front
*** TODO [#C] project properties: height width scale-output- resizable author title license frame-rate
*** TODO [#B] close after eval for some frames
*** TODO [#B] Split MAKE-HALO and selection concept
**** TODO revise selection functions to use flag instead of HALO slot
*** TODO [#B] add more notifications for cut/copy etc
**** TODO Show yellow notification string on modeline
*** TODO [#A] show error bubble and restore value when input incorrect
*** TODO [#A] fix halos not always being in front
*** TODO [#C] don't allow halo on properties dialog
*** TODO [#C] ENTER should update value in property field
*** TODO [#C] fix menubar not drawing over dialogs
......@@ -813,3 +812,43 @@
:ARCHIVE_TODO: TODO
:END:
*** TODO TAP MENUBAR should forward click to menu
** DONE [#B] fix *untitled-buffer* not being added to list
CLOSED: [2017-04-22 Sat 07:54]
:PROPERTIES:
:ARCHIVE_TIME: 2017-04-22 Sat 12:00
:ARCHIVE_FILE: ~/xelf/tasks.org
:ARCHIVE_OLPATH: Task list/fix dialog boxes
:ARCHIVE_CATEGORY: tasks
:ARCHIVE_TODO: DONE
:END:
** DONE fix dialog centering issue
CLOSED: [2017-04-22 Sat 16:53]
:PROPERTIES:
:ARCHIVE_TIME: 2017-04-22 Sat 16:57
:ARCHIVE_FILE: ~/xelf/tasks.org
:ARCHIVE_OLPATH: Task list/fix dialog boxes
:ARCHIVE_CATEGORY: tasks
:ARCHIVE_TODO: DONE
:END:
** DONE [#A] close after eval for some frames
CLOSED: [2017-04-22 Sat 16:57]
:PROPERTIES:
:ARCHIVE_TIME: 2017-04-22 Sat 16:57
:ARCHIVE_FILE: ~/xelf/tasks.org
:ARCHIVE_OLPATH: Task list/fix dialog boxes
:ARCHIVE_CATEGORY: tasks
:ARCHIVE_TODO: DONE
:END:
** DONE [#A] basic switch-to-buffer textbox
CLOSED: [2017-04-22 Sat 16:57]
:PROPERTIES:
:ARCHIVE_TIME: 2017-04-22 Sat 16:57
:ARCHIVE_FILE: ~/xelf/tasks.org
:ARCHIVE_OLPATH: Task list/fix dialog boxes
:ARCHIVE_CATEGORY: tasks
:ARCHIVE_TODO: DONE
:END:
......@@ -64,6 +64,9 @@
(trace xelf::open-shell)
(trace xelf::focus-on)
(trace xelf::close-shell)
(trace switch-to-buffer)
(trace all-buffer-names)
;; (trace xelf::drag-candidate)
;; (trace xelf::drag-maybe)
;; (trace xelf::drag-fail)
......
......@@ -5372,7 +5372,9 @@ Returns a newly allocated list."
;; Legacy GUI compatibility:1 ends here
;; [[file:~/xelf/xelf.org::*Legacy%20GUI%20compatibility][Legacy GUI compatibility:2]]
(defmethod proper-name ((self node))
(defmethod freeze ((self node)) nil)
(defmethod proper-name ((self node))
(pretty-string (class-name (class-of self))))
(defmethod initialize-instance :after ((self node) &key))
......
......@@ -5356,6 +5356,8 @@ in the future.
#+end_src
#+begin_src lisp
(defmethod freeze ((self node)) nil)
(defmethod proper-name ((self node))
(pretty-string (class-name (class-of self))))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment