0378dd50 |
; Copyright (c) 2014 Edward Langley
; All rights reserved.
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions
; are met:
; Redistributions of source code must retain the above copyright notice,
; this list of conditions and the following disclaimer.
; Redistributions in binary form must reproduce the above copyright
; notice, this list of conditions and the following disclaimer in the
; documentation and/or other materials provided with the distribution.
; Neither the name of the project's author nor the names of its
; contributors may be used to endorse or promote products derived from
; this software without specific prior written permission.
; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
; FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
; HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
; TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
cf79e684 |
(require 'asdf)
(asdf:load-system 'quicklisp)
|
0378dd50 |
(asdf:load-system :cl-cffi-gtk)
|
cf79e684 |
(ql:quickload :cl-fad)
(ql:quickload :x.let-star)
|
0378dd50 |
|
278be5ac |
(defpackage :notes-app
|
0378dd50 |
(:use :gtk :gdk :gdk-pixbuf :gobject
|
cf79e684 |
:glib :gio :pango :cairo :common-lisp
:cl-fad :x.let-star)
(:shadowing-import-from x.let-star let*)
(:export main))
|
0378dd50 |
|
278be5ac |
(in-package :notes-app)
|
0378dd50 |
;(macroexpand-1 '(on (clicked button) (__)
; (declare (ignore __))
; (format t "Button 1 was pressed")))
(defmacro on ((sig target) bind &body body)
|
278be5ac |
"Bind a signal handler: note that this intentionally shadows whatever
the 'bind' argument is"
|
0378dd50 |
`(g-signal-connect ,target ,(string-downcase (symbol-name sig))
(lambda ,bind
,@body)))
|
278be5ac |
(defmacro thread-signal ((sig target) bind callback)
"Bind a signal handler: note that this intentionally shadows whatever
the 'bind' argument is"
`(g-signal-connect ,target ,(string-downcase (symbol-name sig)) ,callback))
|
cf79e684 |
(defmacro mainloop (fname winvar title width height &body body)
`(defun ,fname ()
(within-main-loop
(let ((,winvar (make-instance 'gtk-window
:title ,title
:type :toplevel
:default-width ,width
:default-height ,height)))
(on (destroy ,winvar) (widget)
(declare (ignore widget))
(leave-gtk-main))
,@body
|
278be5ac |
(gtk-widget-show-all ,winvar)))
(join-gtk-main)))
|
cf79e684 |
;(macroexpand-1
; (quote
; (declare-paned-widget (:orientation :vertical)
; (declare-scroll-window () list-view)
; (declare-scroll-window (:wrap-mode :word) text-view))))
;(let ((paned (make-instance 'gtk :orientation :vertical)))
; (let ((scroller (make-instance 'gtk-scroll-window)))
; (gtk-container-add list-view))
; (let ((scroller (make-instance 'gtk-scroll-window :wrap-mode :word)))
; (gtk-container-add text-view)))
(defmacro declare-scroll-window (initializers child)
(let ((sw-sym (gensym)))
`(let ((,sw-sym (make-instance 'gtk-scrolled-window ,@initializers)))
(gtk-container-add ,sw-sym ,child)
,sw-sym)))
(defmacro declare-paned-widget (initializers child1 child2)
(let ((paned-sym (gensym)))
`(let ((,paned-sym (make-instance 'gtk-paned ,@initializers)))
(gtk-paned-add1 ,paned-sym ,child1)
(gtk-paned-add2 ,paned-sym ,child2)
,paned-sym)))
|
278be5ac |
(labels ((process-child (child box-sym)
(if (listp child)
(let* ((_initializers
(if (< 2 (length child)) (cddr child) ()))
(initializers (apply #'append _initializers))
(widget (second child)))
(ecase (first child)
(:start `(gtk-box-pack-start ,box-sym
,widget
,@initializers))
(:end `(gtk-box-pack-end ,box-sym
,widget
,@initializers)))))))
(defmacro declare-box (initializers &body children)
(let ((box-sym (gensym)))
`(let ((,box-sym (make-instance 'gtk-box ,@initializers)))
,@(loop for child in children collect (process-child child box-sym))
,box-sym))))
(defmacro declare-toolbar (initializers &body children)
(let ((toolbar-sym (gensym)))
`(let ((,toolbar-sym (gtk-toolbar-new)))
,@(loop for button in children collect
`(gtk-toolbar-insert ,toolbar-sym
(make-instance 'gtk-tool-button ,@button)
-1))
,toolbar-sym)))
|
cf79e684 |
(defun make-list-view (display-list)
(let ((store (make-instance 'gtk-list-store :column-types '("gchararray")))
(list-view (make-instance 'gtk-tree-view :headers-visible nil)))
(gtk-tree-view-set-model list-view store)
(loop for fn in display-list
do (gtk-list-store-set store
(gtk-list-store-append store)
(file-namestring fn)))
(let* ((renderer (make-instance 'gtk-cell-renderer-text))
(column
(gtk-tree-view-column-new-with-attributes "Filename" renderer "text" 0)))
(gtk-tree-view-append-column list-view column))
(values store list-view)))
(defun make-text-view (text)
(let* ((text-view (make-instance 'gtk-text-view :wrap-mode :word))
(buffer (gtk-text-view-get-buffer text-view)))
(gtk-text-buffer-set-text buffer text)
(values buffer text-view)))
|
278be5ac |
(defun get-list-at-path (list-model path)
(let* ((iter (gtk-tree-model-get-iter list-model path)))
(selected (gtk-tree-model-get-value list-model iter 0))) )
(defvar *note-dir* "/home/edwlan/Dropbox/Notes/")
|
cf79e684 |
(mainloop main window "test" 200 200
|
278be5ac |
(let* (((:mval list-model list-view) (make-list-view
(cl-fad:list-directory *note-dir*)))
|
cf79e684 |
((:mval text-buffer text-view) (make-text-view "")))
|
278be5ac |
|
cf79e684 |
(on (row-activated list-view) (tree-view path column)
|
278be5ac |
(let* ((selected (get-list-at-path list-model path))
|
cf79e684 |
(file-contents
|
278be5ac |
(with-open-file (fd (merge-pathnames-as-file *note-dir* selected))
|
cf79e684 |
(let ((seq (make-string (file-length fd))))
(read-sequence seq fd)
seq))))
(gtk-text-buffer-set-text text-buffer file-contents)))
(gtk-container-add window
(declare-paned-widget (:orientation :vertical)
|
278be5ac |
(declare-box
(:orientation :vertical)
(:end
(declare-box
(:orientation :horizontal)
(:start (gtk-entry-new) (:fill t))
(:end
(make-instance 'gtk-button
:use-stock t
:label "gtk-add")
(:expand nil)))
(:expand nil))
(:start
(declare-scroll-window
(:height-request 400)
list-view)
(:fill t)))
(declare-scroll-window
(:wrap-mode :word)
text-view)))))
|
cf79e684 |
;(main)
|
278be5ac |
(labels
|
cf79e684 |
((slot-function (descriptor)
(ecase descriptor
(:start 'gtk-box-pack-start)
(:end 'gtk-box-pack-end)))
(proc-slot (box from-object slot)
(if (equal (first slot) 'QUOTE)
|
278be5ac |
`(gtk-box-pack-start ,box (slot-value ,from-object ,slot))
|
cf79e684 |
(ecase (length slot)
(1 `(gtk-box-pack-start ,box (slot-value ,from-object ,(first slot))))
(2 `(,(slot-function (second slot)) ,box (slot-value ,from-object ,(first slot))))))))
(defmacro renderwin (window box from-object &body slots)
(let ((window-sym (gensym))
(box-sym (gensym))
(from-obj-sym (gensym)))
`(let ((,window-sym ,window)
(,box-sym ,box)
(,from-obj-sym ,from-object))
,@(loop for slot in slots collect (proc-slot box-sym from-obj-sym slot))
(gtk-container-add ,window-sym ,box-sym)))))
(defclass mainwin nil
((file-view :initarg :file-view)
(file-list :initarg :file-list)))
(defun wrap-with-scrollwindow (widg &key (hscrpolicy :automatic) (vscrpolicy :automatic))
(let ((scroller (make-instance 'gtk-scrolled-window
:hscrollbar-policy hscrpolicy
:vscrollbar-policy vscrpolicy)))
(gtk-container-add scroller widg)
scroller))
|
0378dd50 |
|