├── etc ├── font-test.doc ├── textedit.png ├── unblocked.png └── lisp.exe.manifest ├── docs ├── website │ ├── gradient.png │ ├── sourceforge.html │ ├── screenshots.html │ ├── docs.html │ ├── download.html │ ├── style.css │ └── index.html └── manual │ ├── graphic-forms-0.9.chm │ ├── gfc-macro-symbols.xml │ ├── gfs-macro-symbols.xml │ ├── gfc-class-symbols.xml │ ├── gfc-function-symbols.xml │ ├── api.xml │ ├── protocols.xml │ ├── miscellaneous-topics.xml │ ├── catalog.xml │ ├── utils.xsl │ ├── graphic-forms.css │ ├── win32-api-table.xml │ ├── graphic-forms.xml │ ├── graphic-forms.xsl │ ├── clhs-table.xml │ ├── README.txt │ ├── legal.xml │ ├── packages.xml │ └── Makefile ├── src ├── demos │ ├── textedit │ │ ├── about.bmp │ │ ├── textedit.ico │ │ └── textedit-document.lisp │ ├── unblocked │ │ ├── about.bmp │ │ ├── red-tile.bmp │ │ ├── blue-tile.bmp │ │ ├── brown-tile.bmp │ │ ├── gold-tile.bmp │ │ ├── green-tile.bmp │ │ ├── pink-tile.bmp │ │ ├── unblocked.ico │ │ ├── double-buffered-event-dispatcher.lisp │ │ ├── unblocked-model.lisp │ │ ├── unblocked-controller.lisp │ │ ├── scoreboard-panel.lisp │ │ ├── tiles-panel.lisp │ │ └── unblocked-window.lisp │ └── demo-utils.lisp ├── tests │ ├── uitoolkit │ │ ├── custom.cur │ │ ├── happy.bmp │ │ ├── computer.png │ │ ├── default.ico │ │ ├── open-folder.gif │ │ ├── blackwhite20x16.bmp │ │ ├── truecolor16x16.bmp │ │ ├── color-unit-tests.lisp │ │ ├── widget-unit-tests.lisp │ │ ├── hello-world.lisp │ │ ├── graphics-context-unit-tests.lisp │ │ ├── layout-unit-tests.lisp │ │ ├── image-unit-tests.lisp │ │ ├── README.txt │ │ ├── scroll-tester.lisp │ │ ├── test-utils.lisp │ │ ├── mock-objects.lisp │ │ ├── image-tester.lisp │ │ ├── flow-layout-unit-tests.lisp │ │ ├── scroll-grid-panel.lisp │ │ ├── border-layout-unit-tests.lisp │ │ ├── scroll-text-panel.lisp │ │ └── icon-bundle-unit-tests.lisp │ └── mcclim │ │ ├── buttons.lisp │ │ ├── draw-test.lisp │ │ └── hello-tester.lisp └── uitoolkit │ ├── system │ ├── native-object.lisp │ ├── system-classes.lisp │ ├── clib.lisp │ ├── system-generics.lisp │ ├── shell32.lisp │ ├── comctl32.lisp │ ├── kernel32.lisp │ ├── comdlg32.lisp │ ├── system-conditions.lisp │ └── datastructs.lisp │ ├── widgets │ ├── message-generics.lisp │ ├── layout-generics.lisp │ ├── layout-classes.lisp │ ├── panel.lisp │ ├── root-window.lisp │ ├── list-item.lisp │ ├── item.lisp │ ├── timer.lisp │ ├── event-source.lisp │ ├── defwindow.lisp │ ├── heap-layout.lisp │ ├── widget-constants.lisp │ ├── color-dialog.lisp │ ├── button.lisp │ ├── item-manager.lisp │ ├── status-bar.lisp │ ├── font-dialog.lisp │ └── display.lisp │ └── graphics │ ├── plugins │ ├── graphics-plugin-packages.lisp │ ├── default │ │ └── file-formats.lisp │ └── imagemagick │ │ └── magick-data-plugin.lisp │ ├── font.lisp │ ├── cursor.lisp │ ├── palette.lisp │ ├── graphics-constants.lisp │ ├── graphics-classes.lisp │ └── font-data.lisp ├── config.lisp ├── .gitignore ├── notes.txt ├── graphic-forms.asd ├── test-package.lisp ├── LICENSE.txt ├── graphic-forms-tests.asd └── graphic-forms-uitoolkit.asd /etc/font-test.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/Graphic-Forms/master/etc/font-test.doc -------------------------------------------------------------------------------- /etc/textedit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/Graphic-Forms/master/etc/textedit.png -------------------------------------------------------------------------------- /etc/unblocked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/Graphic-Forms/master/etc/unblocked.png -------------------------------------------------------------------------------- /docs/website/gradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/Graphic-Forms/master/docs/website/gradient.png -------------------------------------------------------------------------------- /src/demos/textedit/about.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/Graphic-Forms/master/src/demos/textedit/about.bmp -------------------------------------------------------------------------------- /src/demos/unblocked/about.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/Graphic-Forms/master/src/demos/unblocked/about.bmp -------------------------------------------------------------------------------- /src/tests/uitoolkit/custom.cur: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/Graphic-Forms/master/src/tests/uitoolkit/custom.cur -------------------------------------------------------------------------------- /src/tests/uitoolkit/happy.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/Graphic-Forms/master/src/tests/uitoolkit/happy.bmp -------------------------------------------------------------------------------- /src/demos/textedit/textedit.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/Graphic-Forms/master/src/demos/textedit/textedit.ico -------------------------------------------------------------------------------- /src/demos/unblocked/red-tile.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/Graphic-Forms/master/src/demos/unblocked/red-tile.bmp -------------------------------------------------------------------------------- /src/tests/uitoolkit/computer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/Graphic-Forms/master/src/tests/uitoolkit/computer.png -------------------------------------------------------------------------------- /src/tests/uitoolkit/default.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/Graphic-Forms/master/src/tests/uitoolkit/default.ico -------------------------------------------------------------------------------- /docs/manual/graphic-forms-0.9.chm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/Graphic-Forms/master/docs/manual/graphic-forms-0.9.chm -------------------------------------------------------------------------------- /src/demos/unblocked/blue-tile.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/Graphic-Forms/master/src/demos/unblocked/blue-tile.bmp -------------------------------------------------------------------------------- /src/demos/unblocked/brown-tile.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/Graphic-Forms/master/src/demos/unblocked/brown-tile.bmp -------------------------------------------------------------------------------- /src/demos/unblocked/gold-tile.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/Graphic-Forms/master/src/demos/unblocked/gold-tile.bmp -------------------------------------------------------------------------------- /src/demos/unblocked/green-tile.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/Graphic-Forms/master/src/demos/unblocked/green-tile.bmp -------------------------------------------------------------------------------- /src/demos/unblocked/pink-tile.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/Graphic-Forms/master/src/demos/unblocked/pink-tile.bmp -------------------------------------------------------------------------------- /src/demos/unblocked/unblocked.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/Graphic-Forms/master/src/demos/unblocked/unblocked.ico -------------------------------------------------------------------------------- /src/tests/uitoolkit/open-folder.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/Graphic-Forms/master/src/tests/uitoolkit/open-folder.gif -------------------------------------------------------------------------------- /src/tests/uitoolkit/blackwhite20x16.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/Graphic-Forms/master/src/tests/uitoolkit/blackwhite20x16.bmp -------------------------------------------------------------------------------- /src/tests/uitoolkit/truecolor16x16.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/Graphic-Forms/master/src/tests/uitoolkit/truecolor16x16.bmp -------------------------------------------------------------------------------- /config.lisp: -------------------------------------------------------------------------------- 1 | (in-package :cl-user) 2 | 3 | #+load-imagemagick-plugin 4 | (defvar *magick-library-directory* "c:/Program Files/ImageMagick-6.2.6-Q16/") 5 | -------------------------------------------------------------------------------- /docs/manual/gfc-macro-symbols.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /docs/manual/gfs-macro-symbols.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore foo.txt 2 | #foo.txt 3 | # ignore all html 4 | #*.html 5 | # but don't ignore foo.html 6 | #!foo.html 7 | # ignore all .o .a file 8 | #*.[oa] 9 | 10 | *.fasl 11 | *.wx32fsl 12 | *.wx64fsl -------------------------------------------------------------------------------- /src/uitoolkit/system/native-object.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.system) 2 | 3 | (defmethod disposed-p ((obj native-object)) 4 | (null (handle obj))) 5 | 6 | (declaim (inline null-handle-p)) 7 | (defun null-handle-p (handle) 8 | (cffi:null-pointer-p handle)) 9 | -------------------------------------------------------------------------------- /docs/manual/gfc-class-symbols.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/manual/gfc-function-symbols.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/uitoolkit/system/system-classes.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.system) 2 | 3 | (defclass native-object () 4 | ((handle 5 | :reader handle 6 | :initarg :handle 7 | :initform nil)) 8 | (:documentation "This is the base class for all objects that have a native handle representation at the system level.")) 9 | -------------------------------------------------------------------------------- /src/uitoolkit/system/clib.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.system) 2 | 3 | (eval-when (:compile-toplevel :load-toplevel :execute) 4 | (use-package :cffi)) 5 | 6 | (load-foreign-library "msvcrt.dll") 7 | 8 | (defcfun 9 | ("strncpy" strncpy) 10 | :pointer 11 | (dest :pointer) 12 | (src :pointer) 13 | (count :unsigned-int)) 14 | -------------------------------------------------------------------------------- /src/uitoolkit/system/system-generics.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.system) 2 | 3 | (defgeneric dispose (native-object) 4 | (:documentation "Discards native resources and executes other cleanup code.")) 5 | 6 | (defgeneric disposed-p (native-object) 7 | (:documentation "Returns T if the target has had dispose called; nil otherwise.")) 8 | -------------------------------------------------------------------------------- /docs/manual/api.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | API Reference 8 | 9 | 10 | This chapter documents the Graphic-Forms programming interface. 11 | 12 | 13 | &constants; 14 | &protocols; 15 | &gfcpkg; 16 | &gfgpkg; 17 | &gfspkg; 18 | &gfwpkg; 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/manual/protocols.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | Protocols 8 | 9 | 10 | This section discusses the protocols 11 | representing major functional areas of Graphic-Forms. 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/manual/miscellaneous-topics.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | Miscellaneous Topics 8 | 9 | 10 | Sections of this chapter discuss a variety of topics related to 11 | Windows programming with Graphic-Forms. 12 | 13 | 14 | &imdataplugins; 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/tests/mcclim/buttons.lisp: -------------------------------------------------------------------------------- 1 | 2 | (defpackage :clim-graphic-forms-tests 3 | (:use :clim :clim-lisp)) 4 | 5 | (in-package :clim-graphic-forms-tests) 6 | 7 | ;;; 8 | ;;; (run-frame-top-level (make-application-frame 'buttons)) 9 | ;;; 10 | 11 | (define-application-frame buttons () () 12 | (:menu-bar nil) 13 | (:layouts 14 | (default 15 | (vertically (:equalize-width t) 16 | (make-pane 'push-button :label "First"))))) 17 | -------------------------------------------------------------------------------- /src/uitoolkit/widgets/message-generics.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.widgets) 2 | 3 | (defgeneric process-message (object msg wparam lparam) 4 | (:documentation "Process window system messages for UIT-defined window classes. Return an integer status value.")) 5 | 6 | (defgeneric process-subclass-message (object msg wparam lparam) 7 | (:documentation "Process window system messages for subclassed system UI objects. Return an integer status value.")) 8 | -------------------------------------------------------------------------------- /docs/manual/catalog.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /notes.txt: -------------------------------------------------------------------------------- 1 | 2 | - defining scrollbar event GFs [DONE] 3 | 4 | - dispatching scrollbar event notifications (SB_LINEUP, SB_PAGERIGHT, etc) [DONE] 5 | 6 | - definition of a scroll-area mix-in 7 | 8 | * viewport attributes 9 | 10 | * scrollbar policy 11 | 12 | * client area scrolling helper functions 13 | 14 | - scrollbars as controls 15 | 16 | - keyboard interface for scrolling events 17 | 18 | - account for existing scrolling-related interface already implemented 19 | for controls 20 | -------------------------------------------------------------------------------- /graphic-forms.asd: -------------------------------------------------------------------------------- 1 | (terpri) 2 | (format t "Graphic-Forms UI Toolkit~%") 3 | (format t "Copyright (c) 2006-2007 by Jack D. Unrue~%") 4 | (format t "Copyright (C) 2016 by Bo Yao ~%") 5 | (terpri) 6 | 7 | (defsystem graphic-forms 8 | :description "Graphic-Forms UI Toolkit" 9 | :version "0.9.0" 10 | :author "Jack D. Unrue" 11 | :maintainer "Bo Yao " 12 | :licence "BSD" 13 | :depends-on ("graphic-forms-uitoolkit" 14 | "graphic-forms-tests")) 15 | -------------------------------------------------------------------------------- /src/uitoolkit/system/shell32.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.system) 2 | 3 | (eval-when (:compile-toplevel :load-toplevel :execute) 4 | (use-package :cffi)) 5 | 6 | (load-foreign-library "shell32.dll") 7 | 8 | ;;; See this thread: 9 | ;;; 10 | ;;; http://common-lisp.net/pipermail/cffi-devel/2006-December/000971.html 11 | ;;; 12 | ;;; for a discussion of why the following is commented out. 13 | ;;; 14 | #| 15 | (defcfun 16 | ("DllGetVersion" shell-dll-get-version) 17 | HRESULT 18 | (info :pointer)) 19 | |# 20 | -------------------------------------------------------------------------------- /src/tests/mcclim/draw-test.lisp: -------------------------------------------------------------------------------- 1 | (in-package :clim-user) 2 | 3 | (define-application-frame test () 4 | () 5 | (:panes 6 | (display :application)) 7 | (:layouts 8 | (default display))) 9 | 10 | (define-test-command (com-quit :menu t) () 11 | (frame-exit *application-frame*)) 12 | 13 | (defvar *test-frame* nil) 14 | 15 | (defun test () 16 | (flet ((run () 17 | (let ((frame (make-application-frame 'test))) 18 | (setq *test-frame* frame) (run-frame-top-level frame)))) 19 | (bt:make-thread #'run :name "test"))) 20 | -------------------------------------------------------------------------------- /etc/lisp.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | GNU CLISP 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/uitoolkit/system/comctl32.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.system) 2 | 3 | (eval-when (:compile-toplevel :load-toplevel :execute) 4 | (use-package :cffi)) 5 | 6 | (load-foreign-library "comctl32.dll") 7 | 8 | ;;; See this thread: 9 | ;;; 10 | ;;; http://common-lisp.net/pipermail/cffi-devel/2006-December/000971.html 11 | ;;; 12 | ;;; for a discussion of why the following is commented out. 13 | ;;; 14 | #| 15 | (defcfun 16 | ("DllGetVersion" comctl-dll-get-version) 17 | HRESULT 18 | (info :pointer)) 19 | |# 20 | 21 | (defcfun 22 | ("InitCommonControlsEx" init-common-controls) 23 | BOOL 24 | (init LPTR)) 25 | -------------------------------------------------------------------------------- /test-package.lisp: -------------------------------------------------------------------------------- 1 | (in-package :cl-user) 2 | 3 | (defpackage #:graphic-forms.uitoolkit.tests 4 | (:nicknames #:gft) 5 | (:use :common-lisp :lisp-unit) 6 | (:export 7 | #:drawing-tester 8 | #:event-tester 9 | #:hello-world 10 | #:image-tester 11 | #:layout-tester 12 | #:scroll-tester 13 | #:widget-tester 14 | #:textedit 15 | #:unblocked 16 | #:windlg)) 17 | 18 | (in-package #:gft) 19 | 20 | (defvar *gf-dir* (asdf:system-source-directory "graphic-forms-uitoolkit")) 21 | (defvar *gf-tests-dir* (merge-pathnames "src/tests/" *gf-dir*)) 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/tests/uitoolkit/color-unit-tests.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.tests) 2 | 3 | (define-test color-conversion-test 4 | (let ((c1 (gfg:make-color)) 5 | (c2 (gfg:make-color :red 12 :green 34 :blue 56)) 6 | (c3 (gfg:make-color :red 255 :green 128 :blue 0)) 7 | (c4 (gfg:make-color :red 255 :green 255 :blue 255))) 8 | (loop for clr in (list c1 c2 c3 c4) 9 | do (let ((rgb (gfg::color->rgb clr))) 10 | (assert-equal (gfg:color-red clr) (gfg:color-red (gfg::rgb->color rgb))) 11 | (assert-equal (gfg:color-green clr) (gfg:color-green (gfg::rgb->color rgb))) 12 | (assert-equal (gfg:color-blue clr) (gfg:color-blue (gfg::rgb->color rgb))))))) 13 | -------------------------------------------------------------------------------- /docs/website/sourceforge.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Graphic-Forms project 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |

Redirecting to the Graphic-Forms main website...

14 |

If you have not been automatically redirected, click 15 | here.

16 |

17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /docs/website/screenshots.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Graphic-Forms Screenshots 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |

Graphic-Forms screenshots

14 |
15 | 16 |

Screenshots coming soon...stay tuned!

17 | 18 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/uitoolkit/graphics/plugins/graphics-plugin-packages.lisp: -------------------------------------------------------------------------------- 1 | (in-package #:cl-user) 2 | 3 | ;;; 4 | ;;; package for default Win32 graphics plugin 5 | ;;; 6 | (defpackage #:graphic-forms.uitoolkit.graphics.default 7 | (:nicknames #:gfgd) 8 | (:shadow #:load #:type) 9 | (:use #:common-lisp) 10 | (:export 11 | 12 | ;; classes and structs 13 | 14 | ;; constants 15 | 16 | ;; methods, functions, macros 17 | 18 | ;; conditions 19 | )) 20 | 21 | ;;; 22 | ;;; package for ImageMagick graphics plugin 23 | ;;; 24 | (defpackage #:graphic-forms.uitoolkit.graphics.imagemagick 25 | (:nicknames #:gfgim) 26 | (:shadow #:load #:type) 27 | (:use #:common-lisp) 28 | (:export 29 | 30 | ;; classes and structs 31 | 32 | ;; constants 33 | 34 | ;; methods, functions, macros 35 | 36 | ;; conditions 37 | )) 38 | -------------------------------------------------------------------------------- /src/uitoolkit/widgets/layout-generics.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.widgets) 2 | 3 | (defgeneric compute-size (self win width-hint height-hint) 4 | (:documentation "Computes and returns the size of the window's client area based on the layout's strategy.")) 5 | 6 | (defgeneric compute-layout (self win width-hint height-hint) 7 | (:documentation "Returns a list of conses (window . rectangle) describing the new bounds of each child window.")) 8 | 9 | (defgeneric obtain-default (self) 10 | (:documentation "Returns an instance representing default values to be used when none is supplied by the application.") 11 | (:method (self) 12 | (declare (ignorable self)))) 13 | 14 | (defgeneric perform (self window widget-hint height-hint) 15 | (:documentation "Moves and resizes window children based on layout strategy.")) 16 | -------------------------------------------------------------------------------- /src/uitoolkit/system/kernel32.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.system) 2 | 3 | (eval-when (:compile-toplevel :load-toplevel :execute) 4 | (use-package :cffi)) 5 | 6 | (load-foreign-library "kernel32.dll") 7 | 8 | (defcfun 9 | "Beep" 10 | BOOL 11 | (dw-freq DWORD) 12 | (dw-duration DWORD)) 13 | 14 | (defcfun 15 | ("FreeLibrary" free-library) 16 | BOOL 17 | (hmodule HANDLE)) 18 | 19 | (defcfun 20 | ("GetLastError" get-last-error) 21 | DWORD) 22 | 23 | (defcfun 24 | ("GetModuleHandleA" get-module-handle) 25 | HANDLE 26 | (module-name LPTSTR)) 27 | 28 | (defcfun 29 | ("GetProcAddress" get-proc-address) 30 | :pointer 31 | (hmodule HANDLE) 32 | (proc-name LPTSTR)) 33 | 34 | (defcfun 35 | ("LoadLibraryExA" load-library) 36 | HANDLE 37 | (file-name LPTSTR) 38 | (hfile HANDLE) ; currently reserved and must be a NULL pointer 39 | (flags DWORD)) 40 | 41 | -------------------------------------------------------------------------------- /src/uitoolkit/system/comdlg32.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.system) 2 | 3 | (eval-when (:compile-toplevel :load-toplevel :execute) 4 | (use-package :cffi)) 5 | 6 | (load-foreign-library "comdlg32.dll") 7 | 8 | (defcfun 9 | ("ChooseColorA" choose-color) 10 | BOOL 11 | (struct LPTR)) ; choosecolor struct 12 | 13 | (defcfun 14 | ("ChooseFontA" choose-font) 15 | BOOL 16 | (struct LPTR)) ; choosefont struct 17 | 18 | (defcfun 19 | ("CommDlgExtendedError" comm-dlg-extended-error) 20 | DWORD) 21 | 22 | (defcfun 23 | ("FindTextA" find-text) 24 | HANDLE 25 | (fr LPTR)) ; findreplace struct 26 | 27 | (defcfun 28 | ("GetOpenFileNameA" get-open-filename) 29 | BOOL 30 | (ofn LPTR)) ; openfilename struct 31 | 32 | (defcfun 33 | ("GetSaveFileNameA" get-save-filename) 34 | BOOL 35 | (ofn LPTR)) ; openfilename struct 36 | 37 | (defcfun 38 | ("ReplaceTextA" replace-text) 39 | HANDLE 40 | (fr LPTR)) ; findreplace struct 41 | -------------------------------------------------------------------------------- /src/demos/textedit/textedit-document.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.tests) 2 | 3 | (defclass textedit-document () 4 | ((content-modified 5 | :accessor content-modified-of 6 | :initform nil) 7 | (file-path 8 | :accessor file-path-of 9 | :initform nil))) 10 | 11 | (defvar *textedit-model* (make-instance 'textedit-document)) 12 | 13 | (defun load-textedit-doc (path) 14 | (let ((buffer "")) 15 | (with-open-file (input path) 16 | (do ((line (read-line input nil) 17 | (read-line input nil))) 18 | ((null line)) 19 | (if (zerop (length line)) 20 | (setf buffer (concatenate 'string buffer (format nil "~c~c" #\Return #\Newline))) 21 | (setf buffer (concatenate 'string buffer (format nil "~a~c~c" line #\Return #\Newline)))))) 22 | buffer)) 23 | 24 | (defun save-textedit-doc (path buffer) 25 | (with-open-file (output path :direction :output :if-exists :supersede) 26 | (format output buffer))) 27 | -------------------------------------------------------------------------------- /src/tests/uitoolkit/widget-unit-tests.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.tests) 2 | 3 | (define-test class-registration-test 4 | (assert-true (> (gfw::register-panel-window-class) 0) 'gfw::register-panel-class) 5 | (assert-true (> (gfw::register-toplevel-erasebkgnd-window-class) 0) 'gfw::register-toplevel-erasebkgnd-window-class) 6 | (assert-true (> (gfw::register-toplevel-noerasebkgnd-window-class) 0) 'gfw::register-toplevel-noerasebkgnd-window-class) 7 | (assert-true (> (gfw::register-dialog-class) 0) 'gfw::register-dialog-class) 8 | 9 | ;; test registering them again 10 | ;; 11 | (assert-true (> (gfw::register-panel-window-class) 0) 'gfw::register-panel-class) 12 | (assert-true (> (gfw::register-toplevel-erasebkgnd-window-class) 0) 'gfw::register-toplevel-erasebkgnd-window-class) 13 | (assert-true (> (gfw::register-toplevel-noerasebkgnd-window-class) 0) 'gfw::register-toplevel-noerasebkgnd-window-class) 14 | (assert-true (> (gfw::register-dialog-class) 0) 'gfw::register-dialog-class)) 15 | -------------------------------------------------------------------------------- /docs/manual/utils.xsl: -------------------------------------------------------------------------------- 1 | 2 | 7 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/uitoolkit/graphics/font.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.graphics) 2 | 3 | ;;; 4 | ;;; methods 5 | ;;; 6 | 7 | (defmethod data-object ((self font) &optional gc) 8 | (if (null gc) 9 | (error 'gfs:toolkit-error :detail "gc argument required when calling data-object for font")) 10 | (if (or (gfs:disposed-p self) (gfs:disposed-p gc)) 11 | (error 'gfs:disposed-error)) 12 | (font->data (gfs:handle gc) (gfs:handle self))) 13 | 14 | (defmethod gfs:dispose ((self font)) 15 | (let ((hgdi (gfs:handle self))) 16 | (unless (gfs:null-handle-p hgdi) 17 | (gfs::delete-object hgdi))) 18 | (setf (slot-value self 'gfs:handle) nil)) 19 | 20 | (defmethod initialize-instance :after ((self font) &key gc data &allow-other-keys) 21 | (when (or gc data) 22 | (unless (and gc data (typep gc 'graphics-context) (typep data 'font-data)) 23 | (error 'gfs:toolkit-error :detail "font initialize-instance requires graphics-context and font-data")) 24 | (setf (slot-value self 'gfs:handle) (data->font (gfs:handle gc) data)))) 25 | -------------------------------------------------------------------------------- /docs/manual/graphic-forms.css: -------------------------------------------------------------------------------- 1 | div.title, h2.title { 2 | font-size: 16; 3 | font-family: { Arial, Helvetica, sans-serif; } 4 | font-weight: Bold; 5 | border-bottom-style: groove; 6 | padding-bottom: 12px; 7 | } 8 | 9 | h2.subtitle { 10 | font-size: 16; 11 | font-family: { Arial, Helvetica, sans-serif; } 12 | } 13 | 14 | p.title, h3 { 15 | font-size: 14; 16 | font-family: { Arial, Helvetica, sans-serif; } 17 | font-weight: Bold; 18 | } 19 | 20 | div.chapter, div.glossary, div.section { 21 | border-bottom-style: groove; 22 | margin-bottom: 12px; 23 | } 24 | 25 | div.footer { 26 | font-size: 9; 27 | font-family: { Arial, Helvetica, sans-serif; } 28 | } 29 | 30 | div.itemizedlist { 31 | font-size: 12; 32 | font-family: { Arial, Helvetica, sans-serif; } 33 | } 34 | 35 | a, dd, dt, p.normal, span.productname { 36 | font-size: 12; 37 | font-family: { Arial, Helvetica, sans-serif; } 38 | } 39 | 40 | a.small, p.small { 41 | font-size: 11; 42 | font-family: { Arial, Helvetica, sans-serif; } 43 | } 44 | -------------------------------------------------------------------------------- /docs/website/docs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Graphic-Forms Documentation 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |

Graphic-Forms documentation

14 |
15 | 16 |

Programming Reference

17 |

Note: the link above leads to the SourceForge download site, from 18 | where you can download the Reference in HTML Help (CHM) format.

19 | 20 |

FAQ

21 | 22 |

Articles

23 | 24 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/demos/unblocked/double-buffered-event-dispatcher.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.tests) 2 | 3 | (defvar *background-color* (gfg:make-color :red 0 :green #x80 :blue #x80)) 4 | 5 | (defgeneric update-buffer (disp) 6 | (:documentation "Revises the image buffer so that the associated window can be repainted.") 7 | (:method (disp) 8 | (declare (ignorable disp)))) 9 | 10 | (defclass double-buffered-event-dispatcher (gfw:event-dispatcher) 11 | ((image-buffer 12 | :accessor image-buffer-of 13 | :initform nil))) 14 | 15 | (defmethod clear-buffer ((self double-buffered-event-dispatcher) gc) 16 | (gfg:clear gc *background-color*)) 17 | 18 | (defmethod dispose ((self double-buffered-event-dispatcher)) 19 | (let ((image (image-buffer-of self))) 20 | (unless (or (null image) (gfs:disposed-p image)) 21 | (gfs:dispose image)) 22 | (setf (image-buffer-of self) nil))) 23 | 24 | (defmethod initialize-instance :after ((self double-buffered-event-dispatcher) &key buffer-size) 25 | (setf (image-buffer-of self) (make-instance 'gfg:image :size buffer-size))) 26 | 27 | (defmethod gfw:event-paint ((self double-buffered-event-dispatcher) window gc rect) 28 | (declare (ignore window rect)) 29 | (gfg:draw-image gc (image-buffer-of self) (gfs:make-point))) 30 | -------------------------------------------------------------------------------- /docs/manual/win32-api-table.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/tests/uitoolkit/hello-world.lisp: -------------------------------------------------------------------------------- 1 | (in-package #:graphic-forms.uitoolkit.tests) 2 | 3 | (defvar *hello-win* nil) 4 | 5 | (defclass hellowin-events (gfw:event-dispatcher) ()) 6 | 7 | (defun exit-fn (disp item) 8 | (declare (ignore disp item)) 9 | (gfs:dispose *hello-win*) 10 | (setf *hello-win* nil) 11 | (gfw:shutdown 0)) 12 | 13 | (defmethod gfw:event-close ((disp hellowin-events) window) 14 | (declare (ignore window)) 15 | (exit-fn disp nil)) 16 | 17 | (defmethod gfw:event-paint ((disp hellowin-events) window gc rect) 18 | (declare (ignore window rect)) 19 | (gfg:clear gc gfg:*color-white-smoke*) 20 | (setf (gfg:background-color gc) gfg:*color-red*) 21 | (setf (gfg:foreground-color gc) gfg:*color-green*) 22 | (gfg:draw-text gc "Hello World!" (gfs:make-point))) 23 | 24 | (defun hello-world-internal () 25 | (let ((menubar nil)) 26 | (setf *hello-win* (make-instance 'gfw:top-level :dispatcher (make-instance 'hellowin-events) 27 | :style '(:frame))) 28 | (setf menubar (gfw:defmenu ((:item "&File" 29 | :submenu ((:item "E&xit" :callback #'exit-fn)))))) 30 | (setf (gfw:menu-bar *hello-win*) menubar) 31 | (gfw:show *hello-win* t))) 32 | 33 | (defun hello-world () 34 | (gfw:startup "Hello World" #'hello-world-internal)) 35 | -------------------------------------------------------------------------------- /src/uitoolkit/graphics/cursor.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.graphics) 2 | 3 | ;;; 4 | ;;; functions 5 | ;;; 6 | 7 | 8 | ;;; 9 | ;;; methods 10 | ;;; 11 | 12 | (defmethod gfs:dispose ((self cursor)) 13 | (if (gfs:disposed-p self) 14 | (warn 'gfs:toolkit-warning :detail "cursor already disposed")) 15 | (unless (sharedp self) 16 | (gfs::destroy-cursor (gfs:handle self))) 17 | (setf (slot-value self 'gfs:handle) nil)) 18 | 19 | (defmethod initialize-instance :after ((self cursor) &key file hotspot image system 20 | &allow-other-keys) 21 | (let ((resource-id (if system (cffi:make-pointer system)))) 22 | (cond 23 | (resource-id 24 | (setf (slot-value self 'gfs:handle) 25 | (gfs::load-image (cffi:null-pointer) 26 | resource-id 27 | gfs::+image-cursor+ 28 | 0 0 29 | (logior gfs::+lr-defaultsize+ gfs::+lr-shared+))) 30 | (setf (slot-value self 'shared) t)) 31 | (file 32 | (let ((tmp (make-instance 'image :file file))) 33 | (setf (slot-value self 'gfs:handle) (image->hicon tmp)))) 34 | ((typep image 'image) 35 | (setf (slot-value self 'gfs:handle) (image->hicon image hotspot)))))) 36 | -------------------------------------------------------------------------------- /src/uitoolkit/graphics/palette.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.graphics) 2 | 3 | #| 4 | (defun pixel-color (pal pixel-val) 5 | "Returns the color struct corresponding to the given pixel value; the inverse of the pixel function." 6 | (if (direct-p pal) 7 | (error 'toolkit-error :detail "not yet implemented") 8 | (aref (palette-table pal) pixel-val))) 9 | |# 10 | 11 | (defun dump-colors (pal) 12 | (let* ((tmp (palette-table pal)) 13 | (len (length tmp))) 14 | (when (zerop len) 15 | (format t "~%")) 16 | (dotimes (i len) 17 | (let ((clr (aref tmp i))) 18 | (format t "(~a,~a,~a)" (color-red clr) (color-green clr) (color-blue clr)))))) 19 | 20 | (defmethod print-object ((obj palette) stream) 21 | (print-unreadable-object (obj stream :type t) 22 | (format stream "direct: ~a " (palette-direct obj)) 23 | (format stream "mask: (~a,~a,~a) " 24 | (palette-red-mask obj) 25 | (palette-green-mask obj) 26 | (palette-blue-mask obj)) 27 | (format stream "shift: (~a,~a,~a) " 28 | (palette-red-shift obj) 29 | (palette-green-shift obj) 30 | (palette-blue-shift obj)) 31 | (format stream "table: ") 32 | (dump-colors obj))) 33 | 34 | (defmethod size ((obj palette)) 35 | (length (palette-table obj))) 36 | -------------------------------------------------------------------------------- /src/tests/mcclim/hello-tester.lisp: -------------------------------------------------------------------------------- 1 | 2 | (defpackage :clim-graphic-forms-tests 3 | (:use :clim :clim-lisp)) 4 | 5 | (in-package :clim-graphic-forms-tests) 6 | 7 | (define-application-frame hello-frame () 8 | ((message :initform "Foo!" :accessor message)) 9 | (:menu-bar menubar-command-table) 10 | (:panes (some-pane :application :display-function 'display-some-pane)) 11 | (:layouts (default 12 | (vertically (:height 500 :width 400) 13 | (:fill some-pane))))) 14 | 15 | (define-command com-hello () 16 | #+graphic-forms (gfs::debug-print "com-hello called ") 17 | (setf (message *application-frame*) "Hello there!")) 18 | 19 | (define-command com-hi () 20 | #+graphic-forms (gfs::debug-print "com-hi called ") 21 | (setf (message *application-frame*) "Hi there!")) 22 | 23 | (define-command-table menu-command-table 24 | :menu (("Hello" :command com-hello) 25 | ("Howdy" :command com-hi))) 26 | 27 | (define-command-table menubar-command-table 28 | :menu (("Menu" :menu menu-command-table) 29 | ("Quit" :command com-quit-frame))) 30 | 31 | (define-hello-frame-command (com-quit-frame :name "Quit" :menu t) 32 | () 33 | (frame-exit *application-frame*)) 34 | 35 | (defmethod display-some-pane ((frame hello-frame) stream) 36 | #+graphic-forms (gfs::debug-print "display-some-pane called ") 37 | (format stream (message frame))) 38 | -------------------------------------------------------------------------------- /src/uitoolkit/widgets/layout-classes.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.widgets) 2 | 3 | (defclass layout-manager () 4 | ((style 5 | :accessor style-of 6 | :initarg :style 7 | :initform nil) 8 | (left-margin 9 | :accessor left-margin-of 10 | :initarg :left-margin 11 | :initform 0) 12 | (top-margin 13 | :accessor top-margin-of 14 | :initarg :top-margin 15 | :initform 0) 16 | (right-margin 17 | :accessor right-margin-of 18 | :initarg :right-margin 19 | :initform 0) 20 | (bottom-margin 21 | :accessor bottom-margin-of 22 | :initarg :bottom-margin 23 | :initform 0) 24 | (data 25 | :accessor data-of 26 | :initform nil)) 27 | (:documentation "Subclasses implement layout strategies to manage space within windows.")) 28 | 29 | (defclass border-layout (layout-manager) () 30 | (:documentation "Window children are assigned a position on the edges or center of a container.")) 31 | 32 | (defclass flow-layout (layout-manager) 33 | ((spacing 34 | :accessor spacing-of 35 | :initarg :spacing 36 | :initform 0)) 37 | (:documentation "Window children are arranged in a row or column.")) 38 | 39 | (defclass heap-layout (layout-manager) 40 | ((top-child 41 | :accessor top-child-of 42 | :initarg :top-child 43 | :initform nil)) 44 | (:documentation "Window children are stacked one on top of the other.")) 45 | -------------------------------------------------------------------------------- /docs/manual/graphic-forms.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ]> 22 | 23 | 24 | Graphic-Forms 25 | 26 | A Common Lisp user interface toolkit for Windows. 27 | 28 | 29 | 30 | Reference (version VERSION) 31 | 32 | 33 | 34 | &legal; 35 | &introduction; 36 | &api; 37 | &misctopics; 38 | &glossary; 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /docs/website/download.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Graphic-Forms Downloads 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |

Graphic-Forms Downloads

14 |
15 | 16 |

Graphic-Forms is distributed in source code form. Please choose from 17 | one of the following options: 18 | 19 |

    20 |
  • 21 | Download 22 | a release tarball.

    23 |

  • 24 |
  • 25 | Download 26 | the current development tree via anonymous Subversion. 27 | Note: <project-name> is graphic-forms.

    28 |

  • 29 |
  • 30 | Browse 31 | the Subversion repository.

    32 |

  • 33 |
34 |

35 | 36 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/tests/uitoolkit/graphics-context-unit-tests.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.tests) 2 | 3 | (define-test pen-styles-test 4 | (let ((style1 nil) 5 | (style2 '(:solid)) 6 | (style3 '(:dash :flat-endcap)) 7 | (style4 '(:dot :miter-join)) 8 | (style5 '(:alternate :flat-endcap :bevel-join))) 9 | (dotimes (width 3) 10 | (assert-equal (logior gfs::+ps-cosmetic+ 11 | gfs::+ps-null+) 12 | (gfg::compute-pen-style style1 width) 13 | (list style1 width)) 14 | (assert-equal (logior (if (< width 2) gfs::+ps-cosmetic+ gfs::+ps-geometric+) 15 | gfs::+ps-solid+) 16 | (gfg::compute-pen-style style2 width) 17 | (list style2 width)) 18 | (assert-equal (logior gfs::+ps-geometric+ 19 | gfs::+ps-dash+ 20 | gfs::+ps-endcap-flat+) 21 | (gfg::compute-pen-style style3 width) 22 | (list style3 width)) 23 | (assert-equal (logior gfs::+ps-geometric+ 24 | gfs::+ps-dot+ 25 | gfs::+ps-join-miter+) 26 | (gfg::compute-pen-style style4 width) 27 | (list style4 width)) 28 | (assert-equal (logior gfs::+ps-geometric+ 29 | gfs::+ps-alternate+ 30 | gfs::+ps-endcap-flat+ 31 | gfs::+ps-join-bevel+) 32 | (gfg::compute-pen-style style5 width) 33 | (list style5 width))))) 34 | -------------------------------------------------------------------------------- /src/uitoolkit/system/system-conditions.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.system) 2 | 3 | (define-condition toolkit-error (simple-error) 4 | ((detail :reader detail :initarg :detail :initform nil))) 5 | 6 | (defmethod print-object ((obj toolkit-error) stream) 7 | (let ((detail (detail obj))) 8 | (cond 9 | (detail 10 | (format stream "~a" detail)) 11 | (t 12 | (call-next-method))))) 13 | 14 | (define-condition toolkit-warning (simple-warning) 15 | ((detail :reader detail :initarg :detail :initform nil))) 16 | 17 | (defmethod print-object ((obj toolkit-warning) stream) 18 | (let ((detail (detail obj))) 19 | (cond 20 | (detail 21 | (format stream "~a" detail)) 22 | (t 23 | (call-next-method))))) 24 | 25 | (define-condition disposed-error (error) ()) 26 | 27 | (define-condition win32-error (toolkit-error) 28 | ((code :reader code :initarg :code :initform (get-last-error)))) 29 | 30 | (defmethod print-object ((obj win32-error) stream) 31 | (format stream "code ~a: ~a" (code obj) (detail obj))) 32 | 33 | (define-condition win32-warning (toolkit-warning) 34 | ((code :reader code :initarg :code :initform (get-last-error)))) 35 | 36 | (defmethod print-object ((obj win32-warning) stream) 37 | (format stream "code ~a: ~a" (code obj) (detail obj))) 38 | 39 | (define-condition comdlg-error (win32-error) 40 | ((dlg-code :reader dlg-code :initarg :dlg-code :initform (comm-dlg-extended-error)))) 41 | 42 | (defmethod print-object ((obj comdlg-error) stream) 43 | (format stream "common dialog code ~a: ~a" (code obj) (detail obj))) 44 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2006-2007, Jack D. Unrue 2 | Copyright (c) 2016-2017, Bo Yao 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions 7 | are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 16 | 3. Neither the names of the authors nor the names of its contributors 17 | may be used to endorse or promote products derived from this software 18 | without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS "AS IS" AND ANY 21 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DIS- 23 | CLAIMED. IN NO EVENT SHALL THE AUTHORS AND CONTRIBUTORS BE LIABLE FOR ANY 24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /src/uitoolkit/widgets/panel.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.widgets) 2 | 3 | (defparameter *panel-window-classname* "GraphicFormsPanel") 4 | 5 | ;;; 6 | ;;; helper functions 7 | ;;; 8 | 9 | (defun register-panel-window-class () 10 | (register-window-class *panel-window-classname* 11 | (cffi:get-callback 'uit_widgets_wndproc) 12 | gfs::+cs-dblclks+ 13 | -1)) 14 | 15 | ;;; 16 | ;;; methods 17 | ;;; 18 | 19 | (defmethod compute-outer-size ((self panel) desired-client-size) 20 | (declare (ignore self)) 21 | (gfs:copy-size desired-client-size)) 22 | 23 | (defmethod compute-style-flags ((self panel) &rest extra-data) 24 | (declare (ignore extra-data)) 25 | (let ((std-flags (logior gfs::+ws-clipchildren+ gfs::+ws-clipsiblings+ gfs::+ws-child+ gfs::+ws-visible+))) 26 | (loop for sym in (style-of self) 27 | do (ecase sym 28 | ;; styles that can be combined 29 | ;; 30 | (:border 31 | (setf std-flags (logior std-flags gfs::+ws-border+))) 32 | (:horizontal-scrollbar 33 | (setf std-flags (logior std-flags gfs::+ws-hscroll+))) 34 | (:vertical-scrollbar 35 | (setf std-flags (logior std-flags gfs::+ws-vscroll+))))) 36 | (values std-flags gfs::+ws-ex-controlparent+))) 37 | 38 | (defmethod initialize-instance :after ((self panel) &key parent &allow-other-keys) 39 | (if (null parent) 40 | (error 'gfs:toolkit-error :detail "parent is required for panel")) 41 | (if (gfs:disposed-p parent) 42 | (error 'gfs:disposed-error)) 43 | (init-window self *panel-window-classname* #'register-panel-window-class parent "")) 44 | -------------------------------------------------------------------------------- /src/tests/uitoolkit/layout-unit-tests.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.tests) 2 | 3 | (define-test layout-attributes-test 4 | (let ((widget1 (make-instance 'mock-widget :handle (cffi:make-pointer 1234))) 5 | (widget2 (make-instance 'mock-widget :handle (cffi:make-pointer 5678)))) 6 | (let ((data1 (list widget1 (list 'a 1 'b 2))) 7 | (data2 (list widget2 (list 'a 10 'c 30))) 8 | (layout (make-instance 'gfw:layout-manager))) 9 | (setf (slot-value layout 'gfw::data) (list data1 data2)) 10 | (assert-equal 1 (gfw:layout-attribute layout widget1 'a)) 11 | (assert-equal 2 (gfw:layout-attribute layout widget1 'b)) 12 | (let ((tmp (gfw::obtain-children-with-attribute layout 'b))) 13 | (assert-equal 1 (length tmp)) 14 | (assert-true (cffi:pointer-eq (gfs:handle (car (first tmp))) (gfs:handle widget1)))) 15 | (assert-equal 10 (gfw:layout-attribute layout widget2 'a)) 16 | (assert-equal 30 (gfw:layout-attribute layout widget2 'c)) 17 | (let ((tmp (gfw::obtain-children-with-attribute layout 'c))) 18 | (assert-equal 1 (length tmp)) 19 | (assert-true (cffi:pointer-eq (gfs:handle (car (first tmp))) (gfs:handle widget2)))) 20 | (assert-true (null (gfw::obtain-children-with-attribute layout 'd))) 21 | (setf (gfw:layout-attribute layout widget1 'b) 66 22 | (gfw:layout-attribute layout widget2 'd) 100) 23 | (assert-equal 1 (gfw:layout-attribute layout widget1 'a)) 24 | (assert-equal 66 (gfw:layout-attribute layout widget1 'b)) 25 | (assert-equal 10 (gfw:layout-attribute layout widget2 'a)) 26 | (assert-equal 30 (gfw:layout-attribute layout widget2 'c)) 27 | (assert-equal 100 (gfw:layout-attribute layout widget2 'd))))) 28 | -------------------------------------------------------------------------------- /docs/manual/graphic-forms.xsl: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 32 | 33 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /docs/manual/clhs-table.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/tests/uitoolkit/image-unit-tests.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.tests) 2 | 3 | (defun image-data-tester (path) 4 | (let ((d1 (make-instance 'gfg:image-data)) 5 | (d2 nil) 6 | (d3 nil) 7 | (im (make-instance 'gfg:image)) 8 | (hbmp (cffi:null-pointer))) 9 | (unwind-protect 10 | (progn 11 | (gfg:load d1 path) 12 | (cffi:with-foreign-string (ptr path) 13 | (setf hbmp (gfs::load-image nil 14 | ptr 15 | gfs::+image-bitmap+ 16 | 0 0 17 | (logior gfs::+lr-loadfromfile+ 18 | gfs::+lr-createdibsection+)))) 19 | (if (gfs:null-handle-p hbmp) 20 | (error 'gfs:win32-error :detail "load-image failed")) 21 | (setf d2 (gfg::image->data hbmp)) 22 | (assert-equal (gfg:depth d1) (gfg:depth d2) path) 23 | (let ((size1 (gfg:size d1)) 24 | (size2 (gfg:size d2))) 25 | (assert-equal (gfs:size-width size1) (gfs:size-width size2) path) 26 | (assert-equal (gfs:size-height size1) (gfs:size-height size2) path)) 27 | (gfg:load im path) 28 | (setf d3 (gfg:data-object im)) 29 | (assert-equal (gfg:depth d1) (gfg:depth d3) path) 30 | (let ((size1 (gfg:size d1)) 31 | (size2 (gfg:size d3))) 32 | (assert-equal (gfs:size-width size1) (gfs:size-width size2) path) 33 | (assert-equal (gfs:size-height size1) (gfs:size-height size2) path)) 34 | (unless (gfs:disposed-p im) 35 | (gfs:dispose im)) 36 | (unless (gfs:null-handle-p hbmp) 37 | (gfs::delete-object hbmp)))))) 38 | 39 | #| 40 | (define-test image-data-loading-test 41 | (mapc #'image-data-tester '("blackwhite20x16.bmp" "happy.bmp" "truecolor16x16.bmp"))) 42 | |# 43 | -------------------------------------------------------------------------------- /graphic-forms-tests.asd: -------------------------------------------------------------------------------- 1 | (defsystem graphic-forms-tests 2 | :description "Graphic-Forms UI Toolkit Tests" 3 | :depends-on ("lisp-unit" "graphic-forms-uitoolkit") 4 | :components 5 | ((:file "test-package") 6 | (:module "src" 7 | :depends-on ("test-package") 8 | :components 9 | ((:module "demos" 10 | :components 11 | ((:file "demo-utils") 12 | (:module "textedit" 13 | :serial t 14 | :depends-on ("demo-utils") 15 | :components 16 | ((:file "textedit-document") 17 | (:file "textedit-window"))) 18 | (:module "unblocked" 19 | :serial t 20 | :depends-on ("demo-utils") 21 | :components 22 | ((:file "tiles") 23 | (:file "unblocked-model") 24 | (:file "unblocked-controller") 25 | (:file "double-buffered-event-dispatcher") 26 | (:file "scoreboard-panel") 27 | (:file "tiles-panel") 28 | (:file "unblocked-window"))))) 29 | (:module "tests" 30 | :components 31 | ((:module "uitoolkit" 32 | :serial t 33 | :components 34 | (;;; unit tests 35 | (:file "test-utils") 36 | (:file "mock-objects") 37 | (:file "color-unit-tests") 38 | (:file "graphics-context-unit-tests") 39 | (:file "image-unit-tests") 40 | (:file "icon-bundle-unit-tests") 41 | (:file "layout-unit-tests") 42 | (:file "flow-layout-unit-tests") 43 | (:file "widget-unit-tests") 44 | (:file "item-manager-unit-tests") 45 | (:file "misc-unit-tests") 46 | (:file "border-layout-unit-tests") 47 | 48 | ;;; small examples 49 | (:file "hello-world") 50 | (:file "event-tester") 51 | (:file "layout-tester") ; this file finds out that callback sometimes doesn't work well with sbcl, but ok with ccl. try to fix the original sbcl callback patch 52 | (:file "image-tester") 53 | (:file "drawing-tester") 54 | (:file "widget-tester") 55 | (:file "scroll-grid-panel") 56 | (:file "scroll-text-panel") 57 | (:file "scroll-tester") 58 | (:file "windlg"))))))))) 59 | 60 | -------------------------------------------------------------------------------- /src/uitoolkit/widgets/root-window.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.widgets) 2 | 3 | ;;; 4 | ;;; macros and helper functions 5 | ;;; 6 | 7 | (defmacro with-root-window ((win) &body body) 8 | `(let ((,win (make-instance 'root-window))) 9 | (unwind-protect 10 | (progn 11 | ,@body) 12 | (gfs:dispose ,win)))) 13 | 14 | ;;; 15 | ;;; methods 16 | ;;; 17 | 18 | (defmethod gfs:dispose ((self root-window)) 19 | (setf (slot-value self 'gfs:handle) nil)) 20 | 21 | (defmethod (setf dispatcher) (disp (self root-window)) 22 | (declare (ignore disp)) 23 | (error 'gfs:toolkit-error :detail "The root window cannot be assigned an event-dispatcher.")) 24 | 25 | (defmethod enable ((self root-window) flag) 26 | (declare (ignore flag)) 27 | (error 'gfs:toolkit-error :detail "The root window cannot be enabled or disabled.")) 28 | 29 | (defmethod enable-layout ((self root-window) flag) 30 | (declare (ignore flag)) 31 | (error 'gfs:toolkit-error :detail "The root window has no layout functionality.")) 32 | 33 | (defmethod initialize-instance :after ((self root-window) &key) 34 | (setf (slot-value self 'gfs:handle) (gfs::get-desktop-window))) 35 | 36 | (defmethod (setf location) (pnt (self root-window)) 37 | (declare (ignore pnt)) 38 | (error 'gfs:toolkit-error :detail "The root window cannot be repositioned.")) 39 | 40 | (defmethod layout ((self root-window)) 41 | (error 'gfs:toolkit-error :detail "The root window has no layout functionality.")) 42 | 43 | (defmethod owner ((self root-window)) 44 | nil) 45 | 46 | (defmethod pack ((self root-window)) 47 | (error 'gfs:toolkit-error :detail "The root window has no layout functionality.")) 48 | 49 | (defmethod parent ((self root-window)) 50 | nil) 51 | 52 | (defmethod show ((self root-window) flag) 53 | (declare (ignore flag)) 54 | (error 'gfs:toolkit-error :detail "The root window cannot be shown or hidden.")) 55 | 56 | (defmethod text ((self root-window)) 57 | (error 'gfs:toolkit-error :detail "The root window has no title.")) 58 | 59 | (defmethod (setf text) (str (self root-window)) 60 | (declare (ignore str)) 61 | (error 'gfs:toolkit-error :detail "The root window has no title.")) 62 | -------------------------------------------------------------------------------- /docs/manual/README.txt: -------------------------------------------------------------------------------- 1 | 2 | The Programming Reference source consists of XML-based source files, 3 | some of which are DocBook files and others which are transformed 4 | into DocBook, along with custom XSLT and CSS files, and a catalog 5 | file for resolving URIs. Several utilities comprise the translation 6 | process from sources into HTML Help (CHM) format. 7 | 8 | Before anything else, you should install a version of GNU Make 9 | for Windows, since the docs build process is managed with a 10 | makefile. Just install MSYS or Cygwin, if you haven't already. 11 | 12 | Next, you will need a version of xsltproc and its dependencies. The 13 | version of xsltproc that I have had success using is available from: 14 | 15 | http://www.zlatkovic.com/libxml.en.html 16 | 17 | Download and install the following packages: 18 | 19 | - libxslt-1.1.17.win32.zip 20 | - libxml2-2.6.26.win32.zip 21 | - iconv-1.9.2.win32.zip 22 | - zlib-1.2.3.win32.zip 23 | 24 | Note: I did not have success with libxslt from GnuWin32 so I would not 25 | recommend using that version. 26 | 27 | Third, you will need the hhc.exe command-line compiler from the 28 | HTML Help Workshop, available here: 29 | 30 | http://go.microsoft.com/fwlink/?LinkId=14188 31 | 32 | Make sure that your PATH is updated so that the executables and DLLs 33 | obtained from downloading all of those packages can be found. 34 | 35 | In order to translate from DocBook into HTML Help source and then into 36 | a CHM file, open a command prompt and cd into the docs/manual 37 | subdirectory underneath where you installed the Graphic-Forms source. 38 | 39 | Modify the URI values in catalog.xml to suit your particular 40 | environment, then run make on Makefile. A file named 41 | graphic-forms-.chm is created in the current directory. 42 | is the version of Graphic-Forms. Double-click on the 43 | CHM file and start enjoying the Programming Reference :-) 44 | 45 | 46 | More information about configuring DocBook and xsltproc, as well 47 | as a quick tutorial on the whole process, see these links: 48 | 49 | http://www.pnotepad.org/devlog/archives/000173.html 50 | http://www.codeproject.com/winhelp/docbook_howto.asp 51 | 52 | [the end] 53 | -------------------------------------------------------------------------------- /docs/manual/legal.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | Legal Notices 8 | 9 | Copyright © 2006-2007, Jack D. Unrue <jdunrue at gmail dot com> 10 | 11 | 12 | Redistribution and use in source and binary forms, with or without 13 | modification, are permitted provided that the following conditions are met: 14 | 15 | 16 | 1. Redistributions of source code must retain the above copyright notice, 17 | this list of conditions and the following disclaimer. 18 | 19 | 20 | 2. Redistributions in binary form must reproduce the above copyright 21 | notice, this list of conditions and the following disclaimer in the 22 | documentation and/or other materials provided with the distribution. 23 | 24 | 25 | 3. Neither the names of the authors nor the names of its contributors may 26 | be used to endorse or promote products derived from this software without 27 | specific prior written permission. 28 | 29 | 30 | THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS "AS IS" AND ANY 31 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 32 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 33 | DISCLAIMED. IN NO EVENT SHALL THE AUTHORS AND CONTRIBUTORS BE LIABLE 34 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 35 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 36 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 37 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 38 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 39 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 | 41 | 42 | Trademarks 43 | 44 | Windows® is a registered trademark of Microsoft Corporation. Allegro CL® 45 | is a registered trademark of Franz Inc. LispWorks® is a registered trademark of 46 | LispWorks Ltd. All other trademarks used are owned by their respective owners. 47 | 48 | 49 | -------------------------------------------------------------------------------- /docs/manual/packages.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | The symbols in this package correspond to custom components built on top 13 | of the rest of the library which don't necessarily have an immediate 14 | native peer. 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | This package exports the symbols corresponding to graphics meta-data 26 | and drawing operations. This package and GFW together comprise the bulk 27 | of the public API. 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | The symbols in this package correspond to system-level functionality, 39 | including CFFI declarations for functions and data types. Additional 40 | symbols represent key classes, functions, and conditions. 41 | The majority of Graphic-Forms is built on top of this package. 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | This package contains symbols for user interface widget classes, 53 | event-handling methods, and management functions. This package and 54 | GFG together constitute the bulk of the public API. 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /docs/manual/Makefile: -------------------------------------------------------------------------------- 1 | # -*- Mode: Makefile; tab-width: 4; indent-tabs-mode: t -*- 2 | # 3 | # Makefile 4 | # 5 | # Copyright (c) 2006-2007, Jack D. Unrue 6 | # 7 | 8 | VERSION = 0.9 9 | 10 | CHM-DEPS = gfc-package-tmp.xml gfg-package-tmp.xml gfs-package-tmp.xml \ 11 | gfw-package-tmp.xml constants.xml api.xml \ 12 | catalog.xml glossary.xml graphic-forms.xml image-data-plugins.xml \ 13 | introduction.xml legal.xml protocols.xml miscellaneous-topics.xml 14 | 15 | COMMON-DEPS = symbols.xsl packages.xsl clhs-table.xml win32-api-table.xml \ 16 | packages.xml 17 | 18 | GFC-PKG-DEPS = gfc-class-symbols-tmp.xml gfc-function-symbols-tmp.xml gfc-macro-symbols-tmp.xml 19 | 20 | GFG-PKG-DEPS = gfg-class-symbols-tmp.xml gfg-function-symbols-tmp.xml gfg-macro-symbols-tmp.xml 21 | 22 | GFS-PKG-DEPS = gfs-class-symbols-tmp.xml gfs-function-symbols-tmp.xml gfs-macro-symbols-tmp.xml 23 | 24 | GFW-PKG-DEPS = gfw-class-symbols-tmp.xml gfw-function-symbols-tmp.xml gfw-macro-symbols-tmp.xml 25 | 26 | XSLT-PROC = xsltproc --nonet 27 | 28 | graphic-forms-$(VERSION).chm: $(CHM-DEPS) 29 | cat graphic-forms.xml | sed -e 's/VERSION/$(VERSION)/g' > tmp.xml 30 | $(XSLT-PROC) --stringparam version $(VERSION) graphic-forms.xsl tmp.xml 31 | -hhc htmlhelp.hhp; exit 0 # muffle Error Ignored msg due to hhc exit value 1 32 | find . \( -name "*~" -o -name "*.html" -o -name "*.hhk" -o -name "*.hhc" -o -name "*.hhp" \) -exec rm {} \; 33 | 34 | %-symbols-tmp.xml: %-symbols.xml $(COMMON-DEPS) 35 | $(XSLT-PROC) --output $@ symbols.xsl $*-symbols.xml 36 | 37 | gfc-package-tmp.xml: $(GFC-PKG-DEPS) $(COMMON-DEPS) 38 | $(XSLT-PROC) --stringparam nickname gfc --output $@ packages.xsl packages.xml 39 | 40 | gfg-package-tmp.xml: $(GFG-PKG-DEPS) $(COMMON-DEPS) 41 | $(XSLT-PROC) --stringparam nickname gfg --output $@ packages.xsl packages.xml 42 | 43 | gfs-package-tmp.xml: $(GFS-PKG-DEPS) $(COMMON-DEPS) 44 | $(XSLT-PROC) --stringparam nickname gfs --output $@ packages.xsl packages.xml 45 | 46 | gfw-package-tmp.xml: $(GFW-PKG-DEPS) $(COMMON-DEPS) 47 | $(XSLT-PROC) --stringparam nickname gfw --output $@ packages.xsl packages.xml 48 | 49 | clean: 50 | find . \( -name "*-tmp.xml" -o -name "tmp.xml" \) -exec rm {} \; 51 | find . \( -name "*~" -o -name "*.html" -o -name "*.hhk" -o -name "*.hhc" -o -name "*.hhp" \) -exec rm {} \; 52 | 53 | scrub: clean 54 | find . -name "*.chm" -exec rm {} \; 55 | -------------------------------------------------------------------------------- /src/uitoolkit/widgets/list-item.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.widgets) 2 | 3 | ;;; 4 | ;;; helper functions 5 | ;;; 6 | 7 | (defun lb-insert-item (hwnd index label hbmp) 8 | (declare (ignore hbmp)) ; FIXME: re-enable when we support images in list-box 9 | (let ((text (or label ""))) 10 | (cffi:with-foreign-string (str-ptr text) 11 | (let ((retval (gfs::send-message hwnd gfs::+lb-insertstring+ index (cffi:pointer-address str-ptr)))) 12 | (if (< retval 0) 13 | (error 'gfs:toolkit-error :detail (format nil "LB_INSERTSTRING failed: ~d" retval))))))) 14 | 15 | (defun lb-item-height (hwnd) 16 | (let ((height (gfs::send-message hwnd gfs::+lb-getitemheight+ 0 0))) 17 | (if (< height 0) 18 | (error 'gfs:win32-error :detail "LB_GETITEMHEIGHT failed")) 19 | height)) 20 | 21 | (defun lb-item-text-length (hwnd index) 22 | (let ((length (gfs::send-message hwnd gfs::+lb-gettextlen+ index 0))) 23 | (if (< length 0) 24 | (error 'gfs:win32-error :detail "LB_GETTEXTLEN failed")) 25 | length)) 26 | 27 | (defun lb-item-text (hwnd index &optional buffer-size) 28 | (if (or (null buffer-size) (<= buffer-size 0)) 29 | (setf buffer-size (lb-item-text-length hwnd index))) 30 | (cffi:with-foreign-pointer-as-string (str-ptr (1+ buffer-size)) 31 | (if (< (gfs::send-message hwnd gfs::+lb-gettext+ index (cffi:pointer-address str-ptr)) 0) 32 | (error 'gfs:win32-error :detail "LB_GETTEXT failed")) 33 | (cffi:foreign-string-to-lisp str-ptr))) 34 | 35 | ;;; 36 | ;;; methods 37 | ;;; 38 | 39 | (defmethod gfs:dispose ((self list-item)) 40 | (let ((hwnd (gfs:handle self))) 41 | (unless (or (null hwnd) (cffi:null-pointer-p hwnd)) 42 | (let ((owner (get-widget (thread-context) hwnd))) 43 | (if (and owner (cffi:pointer-eq hwnd (gfs:handle owner))) 44 | (gfs::send-message hwnd gfs::+lb-deletestring+ (item-index owner self) 0))))) 45 | (call-next-method)) 46 | 47 | (defmethod select ((self list-item) flag) 48 | (let ((owner (owner self))) 49 | (if flag 50 | (lb-select-item owner (item-index owner self)) 51 | (lb-deselect-item owner (item-index owner self))))) 52 | 53 | (defmethod selected-p ((self list-item)) 54 | (let ((owner (owner self))) 55 | (> (gfs::send-message (gfs:handle self) gfs::+lb-getsel+ (item-index owner self) 0) 0))) 56 | 57 | (defmethod text ((self list-item)) 58 | (let ((hwnd (gfs:handle self))) 59 | (if (or (null hwnd) (cffi:null-pointer-p hwnd)) 60 | "" 61 | (lb-item-text hwnd (item-index (get-widget (thread-context) hwnd) self))))) 62 | -------------------------------------------------------------------------------- /src/demos/unblocked/unblocked-model.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.tests) 2 | 3 | (eval-when (:compile-toplevel :load-toplevel :execute) 4 | (defconstant +max-tile-kinds+ 6) 5 | (defconstant +horz-tile-count+ 17) 6 | (defconstant +vert-tile-count+ 12) 7 | (defconstant +max-levels+ 21)) 8 | 9 | (defvar *points-needed-table* (loop for level from 1 to +max-levels+ 10 | collect (* 250 level level))) 11 | 12 | (defun lookup-level-reached (score) 13 | (loop for entry in *points-needed-table* 14 | for level from 1 15 | until (> entry score) 16 | finally (return level))) 17 | 18 | (defun compute-new-game-tiles () 19 | (collapse-tiles (init-tiles +horz-tile-count+ +vert-tile-count+ (1- +max-tile-kinds+)))) 20 | 21 | (defun accept-shape-p (shape) 22 | (let ((size (shape-size shape)) 23 | (kind (shape-kind shape))) 24 | (and (> size 1) (/= kind 0) (/= kind +max-tile-kinds+)))) 25 | 26 | (defclass unblocked-game-model () 27 | ((score 28 | :accessor score-of 29 | :initform 0) 30 | (shape-data 31 | :accessor shape-data-of 32 | :initform nil) 33 | (original-tiles 34 | :accessor original-tiles-of 35 | :initform nil) 36 | (active-tiles 37 | :accessor active-tiles-of 38 | :initform nil))) 39 | 40 | (defvar *game* (make-instance 'unblocked-game-model)) 41 | 42 | (defun model-new () 43 | (let ((tiles (compute-new-game-tiles))) 44 | (setf (score-of *game*) 0 45 | (original-tiles-of *game*) tiles 46 | (active-tiles-of *game*) tiles))) 47 | 48 | (defun model-rollback () 49 | (setf (score-of *game*) 0 50 | (active-tiles-of *game*) (original-tiles-of *game*))) 51 | 52 | (defun model-tiles () 53 | (active-tiles-of *game*)) 54 | 55 | (defun update-model-score (shape-data) 56 | (incf (score-of *game*) (* 5 (length shape-data)))) 57 | 58 | (defun update-model-tiles (shape-data) 59 | (setf (active-tiles-of *game*) 60 | (if shape-data 61 | (progn 62 | (loop with tmp = (clone-tiles (active-tiles-of *game*)) 63 | for pnt in shape-data do (set-tile tmp pnt 0) 64 | finally (return (collapse-tiles tmp)))) 65 | (original-tiles-of *game*)))) 66 | 67 | (defun regenerate-model-tiles () 68 | (setf (active-tiles-of *game*) (compute-new-game-tiles))) 69 | 70 | (defun model-level () 71 | (lookup-level-reached (score-of *game*))) 72 | 73 | (defun game-points-needed () 74 | (- (nth (1- (model-level)) *points-needed-table*) (score-of *game*))) 75 | 76 | (defun model-score () 77 | (score-of *game*)) 78 | -------------------------------------------------------------------------------- /docs/website/style.css: -------------------------------------------------------------------------------- 1 | 2 | .header { 3 | font-size: medium; 4 | color:#fafa00; 5 | background-image: url("gradient.png"); 6 | background-repeat: repeat-fixed; 7 | background-attachment: fixed; 8 | padding: 1mm 1mm 1mm 5mm; 9 | } 10 | 11 | .footer { 12 | font-size: small; 13 | font-style: italic; 14 | text-align: right; 15 | color:#fafa00; 16 | background-image: url("gradient.png"); 17 | background-repeat: repeat-fixed; 18 | background-attachment: fixed; 19 | padding: 1mm 1mm 1mm 1mm; 20 | } 21 | 22 | .footer a:link { 23 | font-weight:bold; 24 | color:#ffffff; 25 | } 26 | 27 | .footer a:visited { 28 | font-weight:bold; 29 | color:#ffffff; 30 | } 31 | 32 | :link.footerleft { 33 | font-weight:bold; 34 | float: left; 35 | color:#ffffff; 36 | } 37 | 38 | :visited.footerleft { 39 | font-weight:bold; 40 | float: left; 41 | color:#ffffff; 42 | } 43 | 44 | .check {font-size: x-small; 45 | text-align:right;} 46 | 47 | .check a:link { font-weight:bold; 48 | color:#a0a0ff; 49 | text-decoration:underline; } 50 | 51 | .check a:visited { font-weight:bold; 52 | color:#a0a0ff; 53 | text-decoration:underline; } 54 | 55 | .check a:hover { font-weight:bold; 56 | color:#000000; 57 | text-decoration:underline; } 58 | 59 | div.NavBar { 60 | padding: 4px 0px 4px 0px; 61 | float: right; 62 | font-weight:bold; 63 | } 64 | 65 | .barfirst { 66 | padding: 0px 5px 0px 5px; 67 | margin: 0px 3px 0px 0px; 68 | border-width: 0px 0px 0px 1px; 69 | border-style: none none none solid; 70 | } 71 | 72 | .barcenter { 73 | padding: 0px 5px 0px 5px; 74 | margin: 0px 3px 0px 0px; 75 | border-width: 0px 0px 0px 1px; 76 | border-style: none none none solid; 77 | } 78 | 79 | .barlast { 80 | padding: 0px 5px 0px 5px; 81 | border-width: 0px 0px 0px 1px; 82 | border-style: none none none solid; 83 | } 84 | 85 | :hover.barfirst { 86 | padding: 0px 5px 0px 5px; 87 | margin: 0px 3px 0px 0px; 88 | border-width: 0px 0px 0px 1px; 89 | border-style: none none none solid; 90 | background-color:#e4e4e4; 91 | } 92 | 93 | :hover.barcenter { 94 | padding: 0px 5px 0px 5px; 95 | margin: 0px 3px 0px 0px; 96 | border-width: 0px 0px 0px 1px; 97 | border-style: none none none solid; 98 | background-color:#e4e4e4; 99 | } 100 | 101 | :hover.barlast { 102 | padding: 0px 5px 0px 5px; 103 | border-width: 0px 0px 0px 1px; 104 | border-style: none none none solid; 105 | background-color:#e4e4e4; 106 | } 107 | -------------------------------------------------------------------------------- /src/uitoolkit/widgets/item.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.widgets) 2 | 3 | ;;; 4 | ;;; helper functions 5 | ;;; 6 | 7 | (defun create-item-with-callback (howner class-symbol thing disp) 8 | (let ((item nil)) 9 | (cond 10 | ((null disp) 11 | (setf item (make-instance class-symbol :data thing :handle howner))) 12 | ((functionp disp) 13 | (setf item (make-instance class-symbol :data thing :handle howner :callback disp))) 14 | ((typep disp 'gfw:event-dispatcher) 15 | (setf item (make-instance class-symbol :data thing :handle howner :dispatcher disp))) 16 | (t 17 | (error 'gfs:toolkit-error 18 | :detail "callback must be a function, instance of gfw:event-dispatcher, or null"))) 19 | item)) 20 | 21 | (defun items-equal (item1 item2) 22 | (= (item-id item1) (item-id item2))) 23 | 24 | ;;; 25 | ;;; methods 26 | ;;; 27 | 28 | (defmethod check :before ((self item) flag) 29 | (declare (ignore flag)) 30 | (if (gfs:null-handle-p (gfs:handle self)) 31 | (error 'gfs:toolkit-error :detail "null owner handle"))) 32 | 33 | (defmethod checked-p :before ((self item)) 34 | (if (gfs:null-handle-p (gfs:handle self)) 35 | (error 'gfs:toolkit-error :detail "null owner handle"))) 36 | 37 | (defmethod gfs:dispose ((self item)) 38 | (let ((hwnd (gfs:handle self))) 39 | (unless (or (null hwnd) (cffi:null-pointer-p hwnd)) 40 | (let ((owner (get-widget (thread-context) hwnd))) 41 | (if owner 42 | (setf (slot-value owner 'items) 43 | (remove self (slot-value owner 'items) :test #'items-equal)))))) 44 | (delete-tc-item (thread-context) self) 45 | (setf (slot-value self 'gfs:handle) nil)) 46 | 47 | (defmethod initialize-instance :after ((self item) &key callback &allow-other-keys) 48 | (setf (item-id self) (increment-item-id (thread-context))) 49 | (when callback 50 | (unless (typep callback 'function) 51 | (error 'gfs:toolkit-error :detail ":callback value must be a function")) 52 | (setf (dispatcher self) 53 | (make-instance (define-dispatcher (class-name (class-of self)) callback))))) 54 | 55 | (defmethod owner ((self item)) 56 | (let ((hwnd (gfs:handle self))) 57 | (if (gfs:null-handle-p hwnd) 58 | (error 'gfs:toolkit-error :detail "null owner widget handle")) 59 | (let ((widget (get-widget (thread-context) hwnd))) 60 | (if (null widget) 61 | (error 'gfs:toolkit-error :detail "no owner widget")) 62 | widget))) 63 | 64 | (defmethod print-object ((self item) stream) 65 | (print-unreadable-object (self stream :type t) 66 | (format stream "id: ~d " (item-id self)) 67 | (format stream "data: ~a " (data-of self)) 68 | (format stream "handle: ~x " (gfs:handle self)) 69 | (format stream "dispatcher: ~a" (dispatcher self)))) 70 | -------------------------------------------------------------------------------- /src/uitoolkit/widgets/timer.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.widgets) 2 | 3 | ;;; 4 | ;;; helper functions 5 | ;;; 6 | 7 | (defun clamp-delay-values (init-delay delay) 8 | "Adjust delay settings based on system-defined limits." 9 | ;; 10 | ;; SetTimer is going to impose them anyway, so might as 11 | ;; well make the slot values agree with reality. 12 | ;; On original WinXP (pre-SP1) and earlier, delay values less 13 | ;; than USER_TIMER_MINIMUM get set to 1ms, which MS rectified 14 | ;; in later releases. 15 | ;; 16 | (when (and (> init-delay 0) (< init-delay gfs::+user-timer-minimum+)) 17 | (setf init-delay gfs::+user-timer-minimum+)) 18 | (when (> init-delay gfs::+user-timer-maximum+) 19 | (setf init-delay gfs::+user-timer-maximum+)) 20 | (when (and (> delay 0) (< delay gfs::+user-timer-minimum+)) 21 | (setf delay gfs::+user-timer-minimum+)) 22 | (when (> delay gfs::+user-timer-maximum+) 23 | (setf delay gfs::+user-timer-maximum+)) 24 | (values init-delay delay)) 25 | 26 | (defun reset-timer-to-delay (timer delay) 27 | (multiple-value-bind (init-delay clamped) 28 | (clamp-delay-values 0 delay) 29 | (declare (ignore init-delay)) 30 | (let ((tc (thread-context)) 31 | (id (id-of timer))) 32 | (when (zerop id) 33 | (setf (slot-value timer 'id) (increment-widget-id tc)) 34 | (put-timer tc timer)) 35 | (if (zerop (gfs::set-timer (utility-hwnd tc) (id-of timer) clamped (cffi:null-pointer))) 36 | (error 'gfs:win32-error :detail "set-timer failed"))) 37 | clamped)) 38 | 39 | ;;; 40 | ;;; methods 41 | ;;; 42 | 43 | (defmethod (setf delay-of) :around (value (self timer)) 44 | (setf (slot-value self 'delay) (reset-timer-to-delay self value))) 45 | 46 | (defmethod gfs:dispose ((self timer)) 47 | (let ((tc (thread-context))) 48 | (delete-timer tc self) 49 | (gfs::kill-timer (utility-hwnd tc) (id-of self)))) 50 | 51 | (defmethod initialize-instance :after ((self timer) &key) 52 | (if (null (delay-of self)) 53 | (error 'gfs:toolkit-error :detail ":delay value required")) 54 | (if (null (initial-delay-of self)) 55 | (setf (slot-value self 'initial-delay) (delay-of self))) 56 | (multiple-value-bind (init-delay delay) 57 | (clamp-delay-values (initial-delay-of self) (delay-of self)) 58 | (setf (slot-value self 'initial-delay) init-delay) 59 | (setf (slot-value self 'delay) delay))) 60 | 61 | (defmethod enable ((self timer) flag) 62 | (if flag 63 | (progn 64 | ;; use init-delay as the elapse interval for the very first 65 | ;; tick; the interval will be adjusted (or the timer killed) 66 | ;; as part of processing the first event 67 | ;; 68 | (let ((init-delay (initial-delay-of self))) 69 | (if (> init-delay 0) 70 | (reset-timer-to-delay self init-delay) 71 | (setf (delay-of self) (delay-of self))))) 72 | (gfs:dispose self))) 73 | 74 | (defmethod enabled-p ((self timer)) 75 | (get-timer (thread-context) (id-of self))) 76 | -------------------------------------------------------------------------------- /src/uitoolkit/widgets/event-source.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.widgets) 2 | 3 | (defparameter *callback-info* '((gfw:event-activate . (gfw:event-source)) 4 | (gfw:event-arm . (gfw:event-source)) 5 | (gfw:event-modify . (gfw:event-source)) 6 | (gfw:event-select . (gfw:event-source)) 7 | (gfw:event-scroll . (gfw:event-source symbol symbol)))) 8 | 9 | (defun make-specializer-list (disp-class arg-info) 10 | (let ((tmp (mapcar #'find-class arg-info))) 11 | (push disp-class tmp) 12 | tmp)) 13 | 14 | (defun define-dispatcher-for-callbacks (callbacks) 15 | (let ((*print-gensym* nil) 16 | (class (c2mop:ensure-class (gentemp "EDCLASS" :gfgen) 17 | :direct-superclasses '(event-dispatcher)))) 18 | (loop for pair in callbacks 19 | do (let* ((method-sym (car pair)) 20 | (fn (cdr pair)) 21 | (arg-info (cdr (assoc method-sym *callback-info*))) 22 | (args nil)) 23 | `(unless (or (symbolp ,fn) (functionp ,fn)) 24 | (error 'gfs:toolkit-error 25 | :detail "callback must be function or symbol naming function")) 26 | (if (null arg-info) 27 | (error 'gfs:toolkit-error :detail (format nil 28 | "unsupported event method for callbacks: ~a" 29 | method-sym))) 30 | (dotimes (i (1+ (length arg-info))) 31 | (push (gentemp "ARG" :gfgen) args)) 32 | (c2mop:ensure-method (ensure-generic-function method-sym :lambda-list args) 33 | `(lambda ,args (funcall ,fn ,@args)) 34 | :specializers (make-specializer-list class arg-info)))) 35 | class)) 36 | 37 | (defun define-dispatcher (classname callback) 38 | (let ((proto (c2mop:class-prototype (find-class classname)))) 39 | (define-dispatcher-for-callbacks `((,(callback-event-name-of proto) . ,callback))))) 40 | 41 | ;;; 42 | ;;; methods 43 | ;;; 44 | 45 | (defmethod initialize-instance :after ((self event-source) &key callbacks dispatcher &allow-other-keys) 46 | (unless (or dispatcher (null callbacks)) 47 | (let ((class (define-dispatcher-for-callbacks callbacks))) 48 | (setf (dispatcher self) (make-instance (class-name class)))))) 49 | 50 | (defmethod owner :before ((self event-source)) 51 | (if (gfs:disposed-p self) 52 | (error 'gfs:disposed-error))) 53 | 54 | (defmethod parent :before ((self event-source)) 55 | (if (gfs:disposed-p self) 56 | (error 'gfs:disposed-error))) 57 | 58 | (defmethod print-object ((self event-source) stream) 59 | (print-unreadable-object (self stream :type t) 60 | (format stream "handle: ~x " (gfs:handle self)) 61 | (format stream "dispatcher: ~a " (dispatcher self)))) 62 | -------------------------------------------------------------------------------- /src/tests/uitoolkit/README.txt: -------------------------------------------------------------------------------- 1 | 2 | Here is some information on the test programs available in this directory. 3 | You must first load the Graphic-Forms systems as described in the top-level 4 | README file. 5 | 6 | 7 | How To Run Purpose 8 | ------------------------------------------------------------------------------ 9 | 10 | (gft:drawing-tester) Provides a test case for each major drawing operation, 11 | with variations for pen style, pen width, foreground, 12 | and background color settings. Text mode also shows 13 | features like tab expansion, mnemonics, and transparent 14 | text. 15 | 16 | (gft:event-tester) Verifies that events are being delivered and processed. 17 | Mouse events are visible if you press any button while 18 | moving the mouse (of course, mouse move events do not 19 | require a button press). Keyboard events are shown if 20 | you type keys. Mousing over the menus and menu items 21 | shows menu arming events. Also, this is one of the 22 | test cases for setting menu options via DEFMENU. 23 | 24 | (gft:hello-world) A very basic sanity check that we are able to create 25 | a window and repaint it when needed. 26 | 27 | (gft:image-tester) Tests the display of bitmaps in various sizes and 28 | color depths, also showing transparency masks and the 29 | resulting transparent backgrounds. Also, if you've 30 | loaded the ImageMagick plugin as described in the 31 | top-level README, you'll see a PNG image as well. 32 | 33 | (gft:layout-tester) Tests the flow layout manager. Explore the menu tree 34 | to see what operations are possible. Try changing 35 | layout settings and then resize the window. 36 | 37 | (gft:scroll-tester) Provides test cases for scrolling. Simple grid mode 38 | displays a numbered, scrollable grid, where the 39 | step size is 1 pixel. Text mode tests integral 40 | scrolling and resizing support. When switching from 41 | the simple grid to text mode, clicking on the window 42 | border gets the window to reset to the proper boundary. 43 | 44 | (gft:widget-tester) This is a start at a generic widget-testing program. 45 | Currently displays buttons, a check box, list boxes, 46 | sliders, and scrollbars. This is also a test case for 47 | heap layout. 48 | 49 | (gft:windlg) Provides a way to exercise custom dialogs, system 50 | dialogs, and several window styles. Note that the 51 | Borderless window is dismissed when you click within 52 | it using the mouse. 53 | 54 | 55 | [the end] 56 | -------------------------------------------------------------------------------- /src/uitoolkit/widgets/defwindow.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.widgets) 2 | 3 | (defvar *layout-initargs* (make-hash-table)) 4 | (progn 5 | (setf (gethash :border *layout-initargs*) 6 | '(:bottom-margin :horizontal-margins :left-margin 7 | :margins :right-margin :top-margin :vertical-margins)) 8 | (setf (gethash :flow *layout-initargs*) 9 | '(:bottom-margin :horizontal-margins :left-margin 10 | :margins :right-margin :spacing :style :top-margin 11 | :vertical-margins)) 12 | (setf (gethash :heap *layout-initargs*) 13 | '(:bottom-margin :horizontal-margins :left-margin 14 | :margins :right-margin :top-child :top-margin 15 | :vertical-margins))) 16 | 17 | (defun filter-initargs (arg-plist valid-keywords) 18 | "This function filters a putative list of initargs against a list of 19 | allowed keywords. The first return value is the list of valid initargs 20 | with unrecognized keywords and duplicates removed. The second return value 21 | is a list of the invalid keywords (and their values) that were removed." 22 | (let ((clean-args nil) 23 | (bad-args (copy-seq arg-plist))) 24 | (loop for keyword in valid-keywords 25 | do (let ((value (getf arg-plist keyword))) 26 | (when value 27 | (push value clean-args) 28 | (push keyword clean-args) 29 | (loop for result = (remf bad-args keyword) 30 | while result)))) 31 | (values clean-args bad-args))) 32 | 33 | (defun filter-style-keywords (input-keywords valid-keywords) 34 | "This function filters a putative list of style keywords against a list of 35 | allowed style keywords. The first return value is the list of valid keywords 36 | with unrecognized keywords and duplicates removed. The second return value 37 | is a list of the invalid keywords that were removed." 38 | (let ((ok-keywords nil) 39 | (bad-keywords nil)) 40 | (loop for input in input-keywords 41 | do (if (find input valid-keywords) 42 | (push input ok-keywords) 43 | (push input bad-keywords))) 44 | (values ok-keywords bad-keywords))) 45 | 46 | #| 47 | (let ((style-form (getf form :style))) 48 | |# 49 | 50 | (defun extract-layout-definition (form) 51 | (let ((layout-form (getf form :layout))) 52 | (when layout-form 53 | (let ((valid-keywords (gethash (first form) *layout-initargs*))) 54 | (if (endp valid-keywords) 55 | (error 'gfs:toolkit-error 56 | :format-control "form ~a is not a layout definition" 57 | :format-arguments (list form))) 58 | (filter-initargs (rest form) valid-keywords))))) 59 | 60 | #| 61 | (defun rewrite-panel-form (form) 62 | (unless (eql (first form) :panel) 63 | (error 'gfs:toolkit-error 64 | :format-control "form ~a is not a panel definition" 65 | :format-arguments (list form))) 66 | (let ((style (extract-panel-style form)) 67 | (layout ( 68 | |# 69 | -------------------------------------------------------------------------------- /src/demos/unblocked/unblocked-controller.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.tests) 2 | 3 | (defconstant +revealed-duration+ 2000) ; millis 4 | 5 | (defun ctrl-start-game () 6 | (model-new) 7 | (update-status-bar "Ready.") 8 | (update-panel (get-scoreboard-panel)) 9 | (update-panel (get-tiles-panel))) 10 | 11 | (defun ctrl-restart-game () 12 | (model-rollback) 13 | (update-status-bar "Ready.") 14 | (update-panel (get-scoreboard-panel)) 15 | (update-panel (get-tiles-panel))) 16 | 17 | (defun ctrl-reveal-move () 18 | (let ((shape (find-shape (model-tiles) #'accept-shape-p))) 19 | (cond 20 | (shape 21 | (let ((shape-pnts (shape-tile-points shape)) 22 | (timer (make-instance 'gfw:timer :initial-delay +revealed-duration+ 23 | :delay 0 24 | :dispatcher (gfw:dispatcher (get-unblocked-win))))) 25 | (draw-tiles-directly (get-tiles-panel) shape-pnts +max-tile-kinds+) 26 | (gfw:enable timer t))) 27 | (t 28 | (gfs::message-box (gfs:handle (get-unblocked-win)) 29 | "There are no remaining shapes." 30 | "Sorry!" 31 | (logior gfs::+mb-ok+ gfs::+mb-iconinformation+) 32 | 0))))) 33 | 34 | (defun ctrl-start-selection (shape-pnts panel point button) 35 | (let* ((tiles (model-tiles)) 36 | (tile-pnt (window->tiles point)) 37 | (tile-kind (obtain-tile tiles tile-pnt)) 38 | (tmp-table (make-hash-table :test #'equalp))) 39 | (unless (or (null shape-pnts) (find tile-pnt shape-pnts :test #'eql-point)) 40 | (draw-tiles-directly panel shape-pnts tile-kind)) 41 | (if (and (eql button :left-button) (> tile-kind 0)) 42 | (shape-tiles tiles tile-pnt tmp-table)) 43 | (cond 44 | ((> (hash-table-count tmp-table) 1) 45 | (let ((shape-pnts (shape-tile-points tmp-table))) 46 | (draw-tiles-directly panel shape-pnts +max-tile-kinds+) 47 | (values tile-kind shape-pnts))) 48 | (t (values nil nil))))) 49 | 50 | (defun ctrl-finish-selection (shape-pnts shape-kind panel point button) 51 | (let ((tile-pnt (window->tiles point))) 52 | (when (and (eql button :left-button) shape-pnts) 53 | (if (and tile-pnt (find tile-pnt shape-pnts :test #'eql-point)) 54 | (let ((prev-level (model-level)) 55 | (orig-score (score-of *game*))) 56 | (update-model-score shape-pnts) 57 | (update-status-bar (format nil 58 | "Removed ~d tiles for ~d points." 59 | (length shape-pnts) 60 | (- (score-of *game*) orig-score))) 61 | (if (> (model-level) prev-level) 62 | (progn 63 | (regenerate-model-tiles) 64 | (update-status-bar "Ready.")) 65 | (update-model-tiles shape-pnts)) 66 | (update-panel (get-scoreboard-panel)) 67 | (update-panel (get-tiles-panel))) 68 | (draw-tiles-directly panel shape-pnts shape-kind))))) 69 | -------------------------------------------------------------------------------- /src/tests/uitoolkit/scroll-tester.lisp: -------------------------------------------------------------------------------- 1 | (in-package #:graphic-forms.uitoolkit.tests) 2 | 3 | (defvar *scroll-tester-win* nil) 4 | 5 | (defun scroll-tester-exit (disp item) 6 | (declare (ignore disp item)) 7 | (gfs:dispose *scroll-tester-win*) 8 | (setf *scroll-tester-win* nil) 9 | (gfw:shutdown 0)) 10 | 11 | (defclass scroll-tester-events (gfw:scrolling-helper) ()) 12 | 13 | (defmethod gfw:event-close ((disp scroll-tester-events) window) 14 | (declare (ignore window)) 15 | (scroll-tester-exit disp nil)) 16 | 17 | (defun scroll-tester-internal () 18 | (setf *default-pathname-defaults* (merge-pathnames "uitoolkit/" *gf-tests-dir*)) 19 | (let ((layout (make-instance 'gfw:heap-layout)) 20 | (icons (make-instance 'gfg:icon-bundle :file (merge-pathnames "default.ico")))) 21 | (setf *scroll-tester-win* (make-instance 'gfw:top-level 22 | :dispatcher (make-instance 'scroll-tester-events) 23 | :layout layout 24 | :style '(:workspace :horizontal-scrollbar :vertical-scrollbar))) 25 | (setf (gfw:image *scroll-tester-win*) icons) 26 | (let* ((grid-panel (make-scroll-grid-panel *scroll-tester-win*)) 27 | (text-panel (make-scroll-text-panel *scroll-tester-win*)) 28 | (select-grid (lambda (disp item) 29 | (declare (ignore disp item)) 30 | (setf (gfw:top-child-of layout) grid-panel) 31 | (gfw:layout *scroll-tester-win*) 32 | (set-grid-scroll-params *scroll-tester-win*))) 33 | (select-text (lambda (disp item) 34 | (declare (ignore disp item)) 35 | (setf (gfw:top-child-of layout) text-panel) 36 | (gfw:layout *scroll-tester-win*) 37 | (set-text-scroll-params *scroll-tester-win*))) 38 | (manage-tests-menu (lambda (disp menu) 39 | (declare (ignore disp)) 40 | (let ((top (gfw::obtain-top-child *scroll-tester-win*)) 41 | (items (gfw:items-of menu))) 42 | (gfw:check (elt items 0) (eql top grid-panel)) 43 | (gfw:check (elt items 1) (eql top text-panel))))) 44 | (menubar (gfw:defmenu ((:item "&File" 45 | :submenu ((:item "E&xit" :callback #'scroll-tester-exit))) 46 | (:item "&Tests" :callback manage-tests-menu 47 | :submenu ((:item "&Simple Grid" :callback select-grid) 48 | (:item "&Text" :callback select-text))))))) 49 | (setf (gfw:menu-bar *scroll-tester-win*) menubar 50 | (gfw:top-child-of layout) grid-panel)) 51 | (setf (gfw:text *scroll-tester-win*) "Scroll Tester" 52 | (gfw:size *scroll-tester-win*) (gfs:make-size :width 300 :height 275)) 53 | (set-grid-scroll-params *scroll-tester-win*) 54 | (gfw:show *scroll-tester-win* t))) 55 | 56 | (defun scroll-tester () 57 | (gfw:startup "Scroll Tester" #'scroll-tester-internal)) 58 | -------------------------------------------------------------------------------- /src/uitoolkit/graphics/graphics-constants.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.graphics) 2 | 3 | ;;; The following are transcribed from WinGDI.h; 4 | ;;; specify one of them as the value of the char-set 5 | ;;; slot in the font-data structure. 6 | ;;; 7 | (defconstant +ansi-charset+ 0) 8 | (defconstant +default-charset+ 1) 9 | (defconstant +symbol-charset+ 2) 10 | (defconstant +shiftjis-charset+ 128) 11 | (defconstant +hangeul-charset+ 129) 12 | (defconstant +hangul-charset+ 129) 13 | (defconstant +gb2312-charset+ 134) 14 | (defconstant +chinesebig5-charset+ 136) 15 | (defconstant +oem-charset+ 255) 16 | (defconstant +johab-charset+ 130) 17 | (defconstant +hebrew-charset+ 177) 18 | (defconstant +arabic-charset+ 178) 19 | (defconstant +greek-charset+ 161) 20 | (defconstant +turkish-charset+ 162) 21 | (defconstant +vietnamese-charset+ 163) 22 | (defconstant +thai-charset+ 222) 23 | (defconstant +easteurope-charset+ 238) 24 | (defconstant +russian-charset+ 204) 25 | (defconstant +mac-charset+ 77) 26 | (defconstant +baltic-charset+ 186) 27 | 28 | ;;; The following are from WinUser.h; specify one of 29 | ;;; them as the value of the :system keyword arg when 30 | ;;; creating an icon-bundle 31 | ;;; 32 | (defconstant +application-icon+ 32512) 33 | (defconstant +error-icon+ 32513) 34 | (defconstant +information-icon+ 32516) 35 | (defconstant +question-icon+ 32514) 36 | (defconstant +warning-icon+ 32515) 37 | 38 | 39 | ;;; The following are from WinUser.h; specify one of 40 | ;;; them as the value of the :system keyword arg when 41 | ;;; creating an image. 42 | ;;; 43 | (defconstant +app-starting-cursor+ gfs::+ocr-appstarting+) 44 | (defconstant +crosshair-cursor+ gfs::+ocr-cross+) 45 | (defconstant +default-cursor+ gfs::+ocr-normal+) 46 | (defconstant +hand-cursor+ gfs::+ocr-hand+) 47 | (defconstant +help-cursor+ 32651) 48 | (defconstant +ibeam-cursor+ gfs::+ocr-ibeam+) 49 | (defconstant +no-cursor+ gfs::+ocr-no+) 50 | (defconstant +size-all-cursor+ gfs::+ocr-sizeall+) 51 | (defconstant +size-nesw-cursor+ gfs::+ocr-sizenesw+) 52 | (defconstant +size-ns-cursor+ gfs::+ocr-sizens+) 53 | (defconstant +size-nwse-cursor+ gfs::+ocr-sizenwse+) 54 | (defconstant +size-we-cursor+ gfs::+ocr-sizewe+) 55 | (defconstant +up-arrow-cursor+ gfs::+ocr-up+) 56 | (defconstant +wait-cursor+ gfs::+ocr-wait+) 57 | 58 | ;;; Device context color mixing 59 | (defconstant +R2-BLACK+ 1) 60 | (defconstant +R2-COPYPEN+ 13) 61 | (defconstant +R2-MASKNOTPEN+ 3) 62 | (defconstant +R2-MASKPEN+ 9) 63 | (defconstant +R2-MASKPENNOT+ 5) 64 | (defconstant +R2-MERGENOTPEN+ 12) 65 | (defconstant +R2-MERGEPEN+ 15) 66 | (defconstant +R2-MERGEPENNOT+ 14) 67 | (defconstant +R2-NOP+ 11) 68 | (defconstant +R2-NOT+ 6) 69 | (defconstant +R2-NOTCOPYPEN+ 4) 70 | (defconstant +R2-NOTMASKPEN+ 8) 71 | (defconstant +R2-NOTMERGEPEN+ 2) 72 | (defconstant +R2-NOTXORPEN+ 10) 73 | (defconstant +R2-WHITE+ 16) 74 | (defconstant +R2-XORPEN+ 7) 75 | -------------------------------------------------------------------------------- /src/demos/demo-utils.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.tests) 2 | 3 | (defclass demo-about-dialog-events (gfw:event-dispatcher) ()) 4 | 5 | (defmethod gfw:event-close ((disp demo-about-dialog-events) (dlg gfw:dialog)) 6 | (call-next-method) 7 | (gfs:dispose dlg)) 8 | 9 | (defun about-demo (owner image-path title desc) 10 | (let* ((image (make-instance 'gfg:image :file image-path)) 11 | (dlg (make-instance 'gfw:dialog :owner owner 12 | :dispatcher (make-instance 'demo-about-dialog-events) 13 | :layout (make-instance 'gfw:flow-layout 14 | :margins 8 15 | :spacing 8) 16 | :style '(:owner-modal) 17 | :text title)) 18 | (label (make-instance 'gfw:label :parent dlg)) 19 | (text-panel (make-instance 'gfw:panel 20 | :layout (make-instance 'gfw:flow-layout 21 | :margins 0 22 | :spacing 2 23 | :style '(:vertical)) 24 | :parent dlg)) 25 | (line1 (make-instance 'gfw:label 26 | :parent text-panel 27 | :text desc)) 28 | (line2 (make-instance 'gfw:label 29 | :parent text-panel 30 | :text " ")) 31 | (line3 (make-instance 'gfw:label 32 | :parent text-panel 33 | :text (format nil "Copyright (C) 2006-2007 by Jack D. Unrue"))) 34 | (line4 (make-instance 'gfw:label 35 | :parent text-panel 36 | :text "All Rights Reserved.")) 37 | (line5 (make-instance 'gfw:label 38 | :parent text-panel 39 | :text " ")) 40 | (line6 (make-instance 'gfw:label 41 | :parent text-panel 42 | :text " ")) 43 | (btn-panel (make-instance 'gfw:panel 44 | :parent dlg 45 | :layout (make-instance 'gfw:flow-layout 46 | :margins 0 47 | :spacing 0 48 | :style '(:vertical :normalize)))) 49 | (close-btn (make-instance 'gfw:button 50 | :callback (lambda (disp btn) 51 | (declare (ignore disp btn)) 52 | (gfs:dispose dlg)) 53 | :style '(:default-button) 54 | :text "Close" 55 | :parent btn-panel))) 56 | (declare (ignore line1 line2 line3 line4 line5 line6 close-btn)) 57 | (unwind-protect 58 | (gfg:with-image-transparency (image (gfs:make-point)) 59 | (setf (gfw:image label) image)) 60 | (gfs:dispose image)) 61 | (gfw:pack dlg) 62 | (gfw:center-on-owner dlg) 63 | (gfw:show dlg t))) 64 | -------------------------------------------------------------------------------- /src/uitoolkit/system/datastructs.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.system) 2 | 3 | (defstruct point (x 0) (y 0) (z 0)) 4 | 5 | (defstruct size (width 0) (height 0) (depth 0)) 6 | 7 | (defstruct rectangle (location (make-point)) (size (make-size))) 8 | 9 | (defstruct span (start 0) (end 0)) 10 | 11 | (declaim (inline create-rectangle)) 12 | (defun create-rectangle (&key (height 0) (width 0) (x 0) (y 0)) 13 | (make-rectangle :location (make-point :x x :y y) 14 | :size (make-size :width width :height height))) 15 | 16 | (declaim (inline location)) 17 | (defun location (rect) 18 | (rectangle-location rect)) 19 | 20 | (defun (setf location) (pnt rect) 21 | (setf (rectangle-location rect) pnt)) 22 | 23 | (declaim (inline size)) 24 | (defun size (size) 25 | (rectangle-size size)) 26 | 27 | (defun (setf size) (size rect) 28 | (setf (rectangle-size rect) size)) 29 | 30 | (declaim (inline empty-span-p)) 31 | (defun empty-span-p (span) 32 | (= (span-start span) (span-end span))) 33 | 34 | (defun equal-point-p (point1 point2) 35 | (and (= (point-x point1) (point-x point2)) 36 | (= (point-y point1) (point-y point2)))) 37 | 38 | (defun equal-size-p (size1 size2) 39 | (and (= (size-width size1) (size-width size2)) 40 | (= (size-height size1) (size-height size2)))) 41 | 42 | (defmethod cffi:free-translated-object (ptr (type point-pointer-type) param) 43 | (declare (ignore param)) 44 | (cffi:foreign-free ptr)) 45 | 46 | (defmethod cffi:free-translated-object (ptr (type rect-pointer-type) param) 47 | (declare (ignore param)) 48 | (cffi:foreign-free ptr)) 49 | 50 | (defmethod cffi:translate-from-foreign (ptr (type point-pointer-type)) 51 | (if (cffi:null-pointer-p ptr) 52 | (make-point) 53 | (cffi:with-foreign-slots ((x y) ptr (:struct point)) 54 | (make-point :x x :y y)))) 55 | 56 | ;; TODO: CFFI has changed? 57 | (defmethod cffi:translate-from-foreign (ptr (type point-tclass)) 58 | (if (cffi:null-pointer-p ptr) 59 | (make-point) 60 | (cffi:with-foreign-slots ((x y) ptr (:struct point)) 61 | (make-point :x x :y y)))) 62 | 63 | (defmethod cffi:translate-from-foreign (ptr (type rect-pointer-type)) 64 | (if (cffi:null-pointer-p ptr) 65 | (make-rectangle) 66 | (cffi:with-foreign-slots ((left top right bottom) ptr (:struct rect)) 67 | (let ((pnt (make-point :x left :y top)) 68 | (size (make-size :width (- right left) :height (- bottom top)))) 69 | (make-rectangle :location pnt :size size))))) 70 | 71 | (defmethod cffi:translate-to-foreign ((lisp-pnt point) (type point-pointer-type)) 72 | (let ((ptr (cffi:foreign-alloc '(:struct point)))) 73 | (cffi:with-foreign-slots ((x y) ptr (:struct point)) 74 | (setf x (point-x lisp-pnt) 75 | y (point-y lisp-pnt))) 76 | ptr)) 77 | 78 | (defmethod cffi:translate-to-foreign ((lisp-pnt point) (type point-tclass)) 79 | (let ((ptr (cffi:foreign-alloc '(:struct point)))) 80 | (cffi:with-foreign-slots ((x y) ptr (:struct point)) 81 | (setf x (point-x lisp-pnt) 82 | y (point-y lisp-pnt))) 83 | ptr)) 84 | 85 | (defmethod cffi:translate-to-foreign ((lisp-rect rectangle) (type rect-pointer-type)) 86 | (let ((ptr (cffi:foreign-alloc '(:struct rect))) 87 | (pnt (location lisp-rect)) 88 | (size (size lisp-rect))) 89 | (cffi:with-foreign-slots ((left top right bottom) ptr (:struct rect)) 90 | (setf left (gfs:point-x pnt) 91 | top (gfs:point-y pnt) 92 | right (+ (gfs:point-x pnt) (gfs:size-width size)) 93 | bottom (+ (gfs:point-y pnt) (gfs:size-height size)))) 94 | ptr)) 95 | -------------------------------------------------------------------------------- /src/tests/uitoolkit/test-utils.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.tests) 2 | 3 | (defvar *child-size-1* (gfs:make-size :width 25 :height 5)) 4 | (defvar *child-size-2* (gfs:make-size :width 20 :height 10)) 5 | (defvar *child-size-3* (gfs:make-size :width 40 :height 40)) 6 | 7 | (defun make-flow-layout (kids style &optional spacing left-margin top-margin right-margin bottom-margin) 8 | (let ((layout (make-instance 'gfw:flow-layout 9 | :style style 10 | :spacing (or spacing 0) 11 | :left-margin (or left-margin 0) 12 | :top-margin (or top-margin 0) 13 | :right-margin (or right-margin 0) 14 | :bottom-margin (or bottom-margin 0)))) 15 | (loop for kid in kids do (gfw::append-layout-item layout kid)) 16 | layout)) 17 | 18 | (defun make-border-layout (kids &optional left-margin top-margin right-margin bottom-margin) 19 | (let ((layout (make-instance 'gfw:border-layout 20 | :left-margin (or left-margin 0) 21 | :top-margin (or top-margin 0) 22 | :right-margin (or right-margin 0) 23 | :bottom-margin (or bottom-margin 0)))) 24 | (loop for kid in kids 25 | for region in '(:top :right :bottom :left :center) 26 | when kid 27 | do (progn 28 | (gfw::append-layout-item layout kid) 29 | (setf (gfw:layout-attribute layout kid region) t))) 30 | layout)) 31 | 32 | (defun validate-image (image expected-size expected-depth) 33 | (declare (ignore expected-depth)) 34 | (assert-false (null image)) 35 | (assert-false (gfs:disposed-p image)) 36 | ;; (assert-equal expected-depth (gfg:depth image)) ; FIXME: image->data needed 37 | (assert-equality #'gfs:equal-size-p expected-size (gfg:size image))) 38 | 39 | (defun validate-rects (entries expected-rects) 40 | (assert-equal (length expected-rects) (length entries)) 41 | (let ((actual-rects (loop for entry in entries collect (cdr entry)))) 42 | (mapc #'(lambda (expected actual) 43 | (let ((pnt-a (gfs:location actual)) 44 | (sz-a (gfs:size actual))) 45 | (assert-equal (first expected) (gfs:point-x pnt-a)) 46 | (assert-equal (second expected) (gfs:point-y pnt-a)) 47 | (assert-equal (third expected) (gfs:size-width sz-a)) 48 | (assert-equal (fourth expected) (gfs:size-height sz-a)))) 49 | expected-rects 50 | actual-rects))) 51 | 52 | (defmacro define-layout-test (name width-hint height-hint 53 | expected-width expected-height 54 | customizer expected-rects 55 | factory &rest factory-args) 56 | (let ((layout (gensym)) 57 | (size (gensym)) 58 | (dummy (gensym)) 59 | (data (gensym))) 60 | `(define-test ,name 61 | (let* ((,layout (apply ,factory (list ,@factory-args))) 62 | (,dummy (if ,customizer (funcall ,customizer ,layout))) 63 | (,size (gfw::compute-size ,layout *mock-container* ,width-hint ,height-hint)) 64 | (,data (gfw::compute-layout ,layout *mock-container* ,width-hint ,height-hint))) 65 | (declare (ignore ,dummy)) 66 | (assert-equal ,expected-width (gfs::size-width ,size)) 67 | (assert-equal ,expected-height (gfs::size-height ,size)) 68 | (validate-rects ,data ,expected-rects))))) 69 | -------------------------------------------------------------------------------- /src/uitoolkit/widgets/heap-layout.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.widgets) 2 | 3 | ;;; 4 | ;;; helper functions 5 | ;;; 6 | 7 | (defun obtain-top-child (window) 8 | (let* ((layout (layout-of window)) 9 | (top (top-child-of layout))) 10 | (if top 11 | top 12 | (car (first (compute-layout layout window -1 -1)))))) 13 | 14 | ;;; 15 | ;;; methods 16 | ;;; 17 | 18 | (defmethod compute-size ((self heap-layout) (container layout-managed) width-hint height-hint) 19 | (cleanup-disposed-items self) 20 | (let ((size (gfs:make-size))) 21 | (mapc (lambda (item) 22 | (let ((kid-size (preferred-size (first item) width-hint height-hint))) 23 | (setf (gfs:size-width size) (max (gfs:size-width size) 24 | (gfs:size-width kid-size)) 25 | (gfs:size-height size) (max (gfs:size-height size) 26 | (gfs:size-height kid-size))))) 27 | (data-of self)) 28 | (incf (gfs:size-width size) (+ (left-margin-of self) (right-margin-of self))) 29 | (incf (gfs:size-height size) (+ (top-margin-of self) (bottom-margin-of self))) 30 | size)) 31 | 32 | (defmethod compute-layout ((self heap-layout) (container layout-managed) width-hint height-hint) 33 | (declare (ignore width-hint height-hint)) 34 | (cleanup-disposed-items self) 35 | (let ((size (client-size container)) 36 | (sbar (if (or (typep container 'top-level) (typep container 'dialog)) 37 | (status-bar-of container)))) 38 | (if sbar 39 | (decf (gfs:size-height size) (gfs:size-height (preferred-size sbar -1 -1)))) 40 | (let* ((horz-margin (+ (left-margin-of self) (right-margin-of self))) 41 | (vert-margin (+ (top-margin-of self) (bottom-margin-of self))) 42 | (bounds (gfs:create-rectangle :x (left-margin-of self) 43 | :y (top-margin-of self) 44 | :width (- (gfs:size-width size) 45 | horz-margin) 46 | :height (- (gfs:size-height size) 47 | vert-margin)))) 48 | (mapcar (lambda (item) (cons (first item) bounds)) (data-of self))))) 49 | 50 | (defmethod perform ((self heap-layout) (container layout-managed) width-hint height-hint) 51 | (if (layout-p container) 52 | (let ((top (top-child-of self)) 53 | (kid-specs (compute-layout self container width-hint height-hint))) 54 | (let ((spec (if top 55 | (find-if (lambda (x) (eql x top)) kid-specs :key #'car) 56 | (progn 57 | (setf top (car (first kid-specs))) 58 | (first kid-specs))))) 59 | (if spec 60 | (let ((bounds (cdr spec))) 61 | (setf (gfs:size bounds) (gfs::clamp-size (gfs:size bounds) 62 | (slot-value top 'min-size) 63 | (slot-value top 'max-size))) 64 | (setf (cdr spec) bounds)))) 65 | (arrange-hwnds kid-specs (lambda (item) 66 | (if (eql top item) 67 | (logior +window-pos-flags+ gfs::+swp-showwindow+) 68 | (logior +window-pos-flags+ gfs::+swp-hidewindow+))))))) 69 | 70 | (defmethod (setf top-child-of) :after (child (self heap-layout)) 71 | (unless (typep child 'widget) 72 | (error 'gfs:toolkit-error :detail "top child must be an instance of a widget subclass"))) 73 | -------------------------------------------------------------------------------- /src/uitoolkit/widgets/widget-constants.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.widgets) 2 | 3 | 4 | (defconstant +vk-lbutton+ 1) 5 | (defconstant +vk-rbutton+ 2) 6 | (defconstant +vk-cancel+ 3) 7 | (defconstant +vk-mbutton+ 4) 8 | 9 | (defconstant +vk-break+ #x03) 10 | (defconstant +vk-backspace+ #x08) 11 | (defconstant +vk-tab+ #x09) 12 | (defconstant +vk-clear+ #x0C) ; numpad-5 when numlock off 13 | (defconstant +vk-return+ #x0D) 14 | (defconstant +vk-shift+ #x10) 15 | (defconstant +vk-control+ #x11) 16 | (defconstant +vk-alt+ #x12) 17 | (defconstant +vk-pause+ #x13) 18 | (defconstant +vk-caps-lock+ #x14) 19 | (defconstant +vk-escape+ #x1B) 20 | (defconstant +vk-page-up+ #x21) 21 | (defconstant +vk-page-down+ #x22) 22 | (defconstant +vk-end+ #x23) 23 | (defconstant +vk-home+ #x24) 24 | (defconstant +vk-left+ #x25) 25 | (defconstant +vk-up+ #x26) 26 | (defconstant +vk-right+ #x27) 27 | (defconstant +vk-down+ #x28) 28 | (defconstant +vk-insert+ #x2D) 29 | (defconstant +vk-delete+ #x2E) 30 | (defconstant +vk-help+ #x2F) 31 | (defconstant +vk-left-win+ #x5B) 32 | (defconstant +vk-right-win+ #x5C) 33 | (defconstant +vk-applications+ #x5D) 34 | (defconstant +vk-numpad-0+ #x60) 35 | (defconstant +vk-numpad-1+ #x61) 36 | (defconstant +vk-numpad-2+ #x62) 37 | (defconstant +vk-numpad-3+ #x63) 38 | (defconstant +vk-numpad-4+ #x64) 39 | (defconstant +vk-numpad-5+ #x65) 40 | (defconstant +vk-numpad-6+ #x66) 41 | (defconstant +vk-numpad-7+ #x67) 42 | (defconstant +vk-numpad-8+ #x68) 43 | (defconstant +vk-numpad-9+ #x69) 44 | (defconstant +vk-numpad-*+ #x6A) 45 | (defconstant +vk-numpad-++ #x6B) 46 | (defconstant +vk-numpad--+ #x6D) 47 | (defconstant +vk-numpad-.+ #x6E) 48 | (defconstant +vk-numpad-/+ #x6F) 49 | (defconstant +vk-numpad-f1+ #x70) 50 | (defconstant +vk-numpad-f2+ #x71) 51 | (defconstant +vk-numpad-f3+ #x72) 52 | (defconstant +vk-numpad-f4+ #x73) 53 | (defconstant +vk-numpad-f5+ #x74) 54 | (defconstant +vk-numpad-f6+ #x75) 55 | (defconstant +vk-numpad-f7+ #x76) 56 | (defconstant +vk-numpad-f8+ #x77) 57 | (defconstant +vk-numpad-f9+ #x78) 58 | (defconstant +vk-numpad-f10+ #x79) 59 | (defconstant +vk-numpad-f11+ #x7A) 60 | (defconstant +vk-numpad-f12+ #x7B) 61 | (defconstant +vk-num-lock+ #x90) 62 | (defconstant +vk-scroll-lock+ #x91) 63 | (defconstant +vk-left-shift+ #xA0) 64 | (defconstant +vk-right-shift+ #xA1) 65 | (defconstant +vk-left-control+ #xA2) 66 | (defconstant +vk-right-control+ #xA3) 67 | (defconstant +vk-left-alt+ #xA4) 68 | (defconstant +vk-right-alt+ #xA5) 69 | 70 | (eval-when (:compile-toplevel :load-toplevel :execute) 71 | (defconstant +default-child-style+ (logior gfs::+ws-child+ 72 | gfs::+ws-tabstop+ 73 | gfs::+ws-visible+)) 74 | (defconstant +default-widget-width+ 64) 75 | (defconstant +default-widget-height+ 64) 76 | (defconstant +estimated-text-size+ 32) ; bytes 77 | (defconstant +window-pos-flags+ (logior gfs::+swp-nozorder+ 78 | gfs::+swp-noownerzorder+ 79 | gfs::+swp-noactivate+ 80 | gfs::+swp-nocopybits+))) 81 | 82 | (defvar *empty-rect* (gfs:make-rectangle)) 83 | -------------------------------------------------------------------------------- /src/tests/uitoolkit/mock-objects.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.tests) 2 | 3 | (defconstant +max-widget-size+ 5000) 4 | (defconstant +default-container-width+ 300) 5 | (defconstant +default-container-height+ 200) 6 | 7 | (defvar *default-hwnd* (cffi:make-pointer #xFFFFFFFF)) 8 | 9 | ;;; 10 | ;;; stand-in for a window, used as parent of mock-widget 11 | ;;; 12 | 13 | (defclass mock-container (gfw:layout-managed) 14 | ((location 15 | :accessor location-of 16 | :initarg :location 17 | :initform (gfs:make-point)) 18 | (size 19 | :accessor size-of 20 | :initarg :size 21 | :initform (gfs:make-size :width +default-container-width+ :height +default-container-height+)) 22 | (visibility 23 | :accessor visibility-of 24 | :initarg :visibility 25 | :initform t))) 26 | 27 | (defvar *mock-container* (make-instance 'mock-container)) 28 | 29 | (defmethod gfw:visible-p ((self mock-container)) 30 | (visibility-of self)) 31 | 32 | ;;; 33 | ;;; stand-in for widgets that would be children of windows, to be organized 34 | ;;; via layout managers 35 | ;;; 36 | 37 | (defclass mock-widget (gfw:widget) 38 | ((visibility 39 | :accessor visibility-of 40 | :initform t) 41 | (actual-size 42 | :accessor actual-size-of 43 | :initarg :actual-size 44 | :initform (gfs:make-size)) 45 | (max-size 46 | :initarg :max-size 47 | :initform (gfs:make-size :width +max-widget-size+ :height +max-widget-size+)) 48 | (min-size 49 | :initarg :min-size 50 | :initform (gfs:make-size)))) 51 | 52 | (defmethod initialize-instance :after ((self mock-widget) &key handle &allow-other-keys) 53 | (setf (slot-value self 'gfs:handle) (or handle *default-hwnd*))) 54 | 55 | (defmethod gfw:location ((self mock-widget)) 56 | (gfs:make-point)) 57 | 58 | (defmethod gfw:minimum-size ((self mock-widget)) 59 | (gfs:make-size :width (gfs:size-width (slot-value self 'min-size)) 60 | :height (gfs:size-height (slot-value self 'min-size)))) 61 | 62 | (defmethod gfw:preferred-size ((self mock-widget) width-hint height-hint) 63 | (let ((size (gfs:make-size)) 64 | (min-size (slot-value self 'min-size))) 65 | (if (< width-hint 0) 66 | (setf (gfs:size-width size) (gfs:size-width min-size)) 67 | (setf (gfs:size-width size) width-hint)) 68 | (if (< height-hint 0) 69 | (setf (gfs:size-height size) (gfs:size-height min-size)) 70 | (setf (gfs:size-height size) height-hint)) 71 | size)) 72 | 73 | (defmethod gfw:text-baseline ((self mock-widget)) 74 | (floor (* (gfs:size-height (slot-value self 'min-size)) 3) 4)) 75 | 76 | (defmethod gfw:visible-p ((self mock-widget)) 77 | (visibility-of self)) 78 | 79 | ;;; 80 | ;;; infrastructure for item-manager unit tests 81 | ;;; 82 | 83 | (defclass mock-item (gfw:item) ()) 84 | 85 | (defclass mock-item-manager (gfw:widget gfw:item-manager) ()) 86 | 87 | (defmethod initialize-instance :after ((self mock-item-manager) &key handle items &allow-other-keys) 88 | (setf (slot-value self 'gfs:handle) (or handle *default-hwnd*)) 89 | (if items 90 | (setf (slot-value self 'gfw::items) (gfw::copy-item-sequence (gfs:handle self) items 'mock-item)))) 91 | 92 | (defmethod gfw:append-item ((self mock-item-manager) thing (disp gfw:event-dispatcher) &optional checked disabled classname) 93 | (declare (ignore disabled checked classname)) 94 | (let ((item (gfw::create-item-with-callback (gfs:handle self) 'mock-item thing disp))) 95 | (vector-push-extend item (slot-value self 'gfw::items)) 96 | item)) 97 | 98 | (defmethod (setf gfw:items-of) (new-items (self mock-item-manager)) 99 | (setf (slot-value self 'gfw::items) (gfw::copy-item-sequence (gfs:handle self) new-items 'mock-item))) 100 | -------------------------------------------------------------------------------- /src/tests/uitoolkit/image-tester.lisp: -------------------------------------------------------------------------------- 1 | (in-package #:graphic-forms.uitoolkit.tests) 2 | 3 | (defvar *image-win* nil) 4 | (defvar *happy-image* nil) 5 | (defvar *bw-image* nil) 6 | (defvar *comp-image* nil) 7 | (defvar *folder-image* nil) 8 | (defvar *true-image* nil) 9 | 10 | (defclass image-events (gfw:event-dispatcher) ()) 11 | 12 | (defun dispose-images () 13 | (loop for var in '(*happy-image* *bw-image* *folder-image* *true-image* *comp-image*) 14 | do (unless (null (symbol-value var)) 15 | (gfs:dispose (symbol-value var)) 16 | (setf (symbol-value var) nil)))) 17 | 18 | (defmethod gfw:event-close ((d image-events) window) 19 | (declare (ignore window)) 20 | (dispose-images) 21 | (gfs:dispose *image-win*) 22 | (setf *image-win* nil) 23 | (gfw:shutdown 0)) 24 | 25 | (defun draw-test-image (gc image origin pixel-pnt) 26 | (gfg:draw-image gc image origin) 27 | (incf (gfs:point-x origin) 36) 28 | (gfg:with-image-transparency (image pixel-pnt) 29 | (gfg:draw-image gc (gfg:transparency-mask image) origin) 30 | (incf (gfs:point-x origin) 36) 31 | (gfg:draw-image gc image origin))) 32 | 33 | (defmethod gfw:event-paint ((d image-events) window gc rect) 34 | (declare (ignore window rect)) 35 | (let ((pnt (gfs:make-point)) 36 | (pixel-pnt1 (gfs:make-point)) 37 | (pixel-pnt2 (gfs:make-point :x 15 :y 0)) 38 | (pixel-pnt3 (gfs:make-point :x 31 :y 31))) 39 | (declare (ignorable pixel-pnt3)) 40 | (draw-test-image gc *happy-image* pnt pixel-pnt1) 41 | (setf (gfs:point-x pnt) 0) 42 | (incf (gfs:point-y pnt) 36) 43 | (draw-test-image gc *bw-image* pnt pixel-pnt1) 44 | (setf (gfs:point-x pnt) 0) 45 | (incf (gfs:point-y pnt) 36) 46 | (draw-test-image gc *true-image* pnt pixel-pnt2) 47 | #+load-imagemagick-plugin 48 | (progn 49 | (setf (gfs:point-x pnt) 112) 50 | (setf (gfs:point-y pnt) 0) 51 | (draw-test-image gc *folder-image* pnt pixel-pnt1) 52 | (setf (gfs:point-x pnt) 112) 53 | (incf (gfs:point-y pnt) 36) 54 | (draw-test-image gc *comp-image* pnt pixel-pnt3)))) 55 | 56 | (defun exit-image-fn (disp item) 57 | (declare (ignorable disp item)) 58 | (dispose-images) 59 | (gfs:dispose *image-win*) 60 | (setf *image-win* nil) 61 | (gfw:shutdown 0)) 62 | 63 | (defun load-images () 64 | (let ((*default-pathname-defaults* (merge-pathnames "uitoolkit/" *gf-tests-dir*))) 65 | (setf *happy-image* (make-instance 'gfg:image :file "happy.bmp") 66 | *bw-image* (make-instance 'gfg:image :file "blackwhite20x16.bmp") 67 | *true-image* (make-instance 'gfg:image :file "truecolor16x16.bmp")) 68 | 69 | #+load-imagemagick-plugin 70 | (progn 71 | (setf *folder-image* (make-instance 'gfg:image :file "open-folder.gif") 72 | *comp-image* (make-instance 'gfg:image :file "computer.png"))))) 73 | 74 | (defun image-tester-internal () 75 | (load-images) 76 | (let ((menubar nil)) 77 | (setf *image-win* (make-instance 'gfw:top-level :dispatcher (make-instance 'image-events) 78 | :style '(:workspace))) 79 | (setf (gfw:size *image-win*) (gfs:make-size :width 250 :height 200)) 80 | (setf (gfw:text *image-win*) "Image Tester") 81 | (setf menubar (gfw:defmenu ((:item "&File" 82 | :submenu ((:item "E&xit" :callback #'exit-image-fn)))))) 83 | (setf (gfw:menu-bar *image-win*) menubar) 84 | (setf (gfw:image *image-win*) 85 | (make-instance 'gfg:icon-bundle :file (merge-pathnames "uitoolkit/default.ico" *gf-tests-dir*))) 86 | (gfw:show *image-win* t))) 87 | 88 | (defun image-tester () 89 | (gfw:startup "Image Tester" #'image-tester-internal)) 90 | -------------------------------------------------------------------------------- /docs/website/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Graphic-Forms project 6 | 7 | 8 | 9 | 10 | 11 |
12 |

Graphic-Forms

13 |

A user interface toolkit for Windows.

14 |
15 | 16 | 23 | 24 | 25 |

Introduction

26 | 27 |

Graphic-Forms is a user interface library implemented in 28 | Common Lisp focusing on the 29 | Windows platform. Graphic-Forms is licensed under the 30 | terms of the 31 | BSD License.

32 | 33 |

Long-term goals for this project may include implementing an application 34 | framework on top of the toolkit, a rapid UI development language, a 35 | UI design tool, or some combination thereof.

36 | 37 |

Status

38 | 39 |

The current version is 40 | 41 | 0.9.0, released on xx xxxxxxx 2007.

42 | 43 |

Graphic-Forms is in the alpha stage of development, 44 | meaning new features are still being added and existing features require 45 | considerable testing. Be advised that significant API and behavior changes 46 | are likely for at least several more releases.

47 | 48 |

The supported Lisp implementations are: 49 |

55 | 56 |

Mailing Lists

57 | 68 | 69 |

Trademarks
70 | Windows® is a registered trademark of Microsoft. 71 | Allegro CL® is a registered trademark of Franz Inc. 72 | LispWorks® is a registered trademark of LispWorks Ltd. All other 73 | trademarks used are owned by their respective owners.

74 | 75 | SourceForge Logo 76 | 77 |

78 | 79 |

83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /src/tests/uitoolkit/flow-layout-unit-tests.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.tests) 2 | 3 | (defvar *flow-uniform-kids* (list (make-instance 'mock-widget :min-size *child-size-2*) 4 | (make-instance 'mock-widget :min-size *child-size-2*) 5 | (make-instance 'mock-widget :min-size *child-size-2*))) 6 | (defvar *flow-mixed-kids* (list (make-instance 'mock-widget :min-size *child-size-2*) 7 | (make-instance 'mock-widget :min-size *child-size-1*) 8 | (make-instance 'mock-widget :min-size *child-size-2*))) 9 | 10 | (define-layout-test flow-layout-test1 11 | -1 -1 60 10 12 | nil 13 | '((0 0 20 10) (20 0 20 10) (40 0 20 10)) 14 | #'make-flow-layout *flow-uniform-kids* '(:horizontal)) 15 | 16 | (define-layout-test flow-layout-test2 17 | -1 -1 20 30 18 | nil 19 | '((0 0 20 10) (0 10 20 10) (0 20 20 10)) 20 | #'make-flow-layout *flow-uniform-kids* '(:vertical)) 21 | 22 | (define-layout-test flow-layout-test3 23 | 45 -1 40 20 24 | nil 25 | '((0 0 20 10) (20 0 20 10) (0 10 20 10)) 26 | #'make-flow-layout *flow-uniform-kids* '(:horizontal :wrap)) 27 | 28 | (define-layout-test flow-layout-test4 29 | -1 25 40 20 30 | nil 31 | '((0 0 20 10) (0 10 20 10) (20 0 20 10)) 32 | #'make-flow-layout *flow-uniform-kids* '(:vertical :wrap)) 33 | 34 | (define-layout-test flow-layout-test5 35 | 45 18 40 20 36 | nil 37 | '((0 0 20 10) (20 0 20 10) (0 10 20 10)) 38 | #'make-flow-layout *flow-uniform-kids* '(:horizontal :wrap)) 39 | 40 | (define-layout-test flow-layout-test6 41 | 30 25 40 20 42 | nil 43 | '((0 0 20 10) (0 10 20 10) (20 0 20 10)) 44 | #'make-flow-layout *flow-uniform-kids* '(:vertical :wrap)) 45 | 46 | (define-layout-test flow-layout-test7 47 | -1 -1 68 10 48 | nil 49 | '((0 0 20 10) (24 0 20 10) (48 0 20 10)) 50 | #'make-flow-layout *flow-uniform-kids* '(:horizontal) 4) 51 | 52 | (define-layout-test flow-layout-test8 53 | -1 -1 20 38 54 | nil 55 | '((0 0 20 10) (0 14 20 10) (0 28 20 10)) 56 | #'make-flow-layout *flow-uniform-kids* '(:vertical) 4) 57 | 58 | (define-layout-test flow-layout-test9 59 | 45 18 44 24 60 | nil 61 | '((0 0 20 10) (24 0 20 10) (0 14 20 10)) 62 | #'make-flow-layout *flow-uniform-kids* '(:horizontal :wrap) 4) 63 | 64 | (define-layout-test flow-layout-test10 65 | 30 25 44 24 66 | nil 67 | '((0 0 20 10) (0 14 20 10) (24 0 20 10)) 68 | #'make-flow-layout *flow-uniform-kids* '(:vertical :wrap) 4) 69 | 70 | (define-layout-test flow-layout-test11 71 | -1 -1 63 13 72 | nil 73 | '((3 3 20 10) (23 3 20 10) (43 3 20 10)) 74 | #'make-flow-layout *flow-uniform-kids* '(:horizontal) 0 3 3) 75 | 76 | (define-layout-test flow-layout-test12 77 | -1 -1 23 33 78 | nil 79 | '((0 0 20 10) (0 10 20 10) (0 20 20 10)) 80 | #'make-flow-layout *flow-uniform-kids* '(:vertical) 0 0 0 3 3) 81 | 82 | (define-layout-test flow-layout-test13 83 | -1 -1 75 10 84 | nil 85 | '((0 0 25 10) (25 0 25 10) (50 0 25 10)) 86 | #'make-flow-layout *flow-mixed-kids* '(:horizontal :normalize)) 87 | 88 | (define-layout-test flow-layout-test14 89 | -1 -1 25 30 90 | nil 91 | '((0 0 25 10) (0 10 25 10) (0 20 25 10)) 92 | #'make-flow-layout *flow-mixed-kids* '(:vertical :normalize)) 93 | -------------------------------------------------------------------------------- /src/demos/unblocked/scoreboard-panel.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.tests) 2 | 3 | (defparameter *level-label* "Level:") 4 | (defparameter *points-needed-label* "Points Needed:") 5 | (defparameter *score-label* "Score:") 6 | 7 | (defconstant +scoreboard-text-margin+ 2) 8 | 9 | (defvar *text-color* (gfg:make-color :red 237 :green 232 :blue 14)) 10 | 11 | (defvar *scoreboard-label-font-data* (gfg:make-font-data :face-name "Tahoma" 12 | :point-size 14 13 | :style '(:bold))) 14 | (defvar *scoreboard-value-font-data* (gfg:make-font-data :face-name "Tahoma" 15 | :point-size 14)) 16 | 17 | (defclass scoreboard-panel-events (double-buffered-event-dispatcher) 18 | ((label-font 19 | :accessor label-font-of 20 | :initform nil) 21 | (value-font 22 | :accessor value-font-of 23 | :initform nil))) 24 | 25 | (defmethod dispose ((self scoreboard-panel-events)) 26 | (let ((tmp-font (label-font-of self))) 27 | (unless (null tmp-font) 28 | (gfs:dispose tmp-font) 29 | (setf (label-font-of self) nil)) 30 | (setf tmp-font (value-font-of self)) 31 | (unless (null tmp-font) 32 | (gfs:dispose tmp-font) 33 | (setf (label-font-of self) nil))) 34 | (call-next-method)) 35 | 36 | (defun compute-scoreboard-size () 37 | (let* ((gc (make-instance 'gfg:graphics-context)) 38 | (font (make-instance 'gfg:font :gc gc :data *scoreboard-label-font-data*)) 39 | (metrics (gfg:metrics gc font)) 40 | (buffer-size (gfs:make-size))) 41 | (unwind-protect 42 | (progn 43 | (setf (gfs:size-width buffer-size) (* (+ (length *points-needed-label*) 44 | 2 ; space between label and value 45 | 9) ; number of value characters 46 | (gfg:average-char-width metrics))) 47 | (setf (gfs:size-height buffer-size) (* (gfg:height metrics) 4))) 48 | 49 | (gfs:dispose font) 50 | (gfs:dispose gc)) 51 | buffer-size)) 52 | 53 | (defmethod initialize-instance :after ((self scoreboard-panel-events) &key buffer-size) 54 | (declare (ignorable buffer-size)) 55 | (gfw:with-graphics-context (gc) 56 | (setf (label-font-of self) (make-instance 'gfg:font :gc gc :data *scoreboard-label-font-data*)) 57 | (setf (value-font-of self) (make-instance 'gfg:font :gc gc :data *scoreboard-value-font-data*)))) 58 | 59 | (defmethod draw-scoreboard-row (gc row image-size label-font label-text value-font value) 60 | (let* ((metrics (gfg:metrics gc label-font)) 61 | (text-pnt (gfs:make-point :x +scoreboard-text-margin+ :y (* row (gfg:height metrics)))) 62 | (value-text (format nil "~:d" value))) 63 | (setf (gfg:font gc) label-font) 64 | (setf (gfg:foreground-color gc) *text-color*) 65 | (gfg:draw-text gc label-text text-pnt) 66 | (setf (gfg:font gc) value-font) 67 | (setf (gfs:point-x text-pnt) (- (- (gfs:size-width image-size) +scoreboard-text-margin+) 68 | (gfs:size-width (gfg:text-extent gc value-text)))) 69 | (gfg:draw-text gc value-text text-pnt))) 70 | 71 | (defmethod update-buffer ((self scoreboard-panel-events)) 72 | (let ((gc (make-instance 'gfg:graphics-context :image (image-buffer-of self))) 73 | (label-font (label-font-of self)) 74 | (value-font (value-font-of self)) 75 | (image-size (gfg:size (image-buffer-of self)))) 76 | (unwind-protect 77 | (progn 78 | (clear-buffer self gc) 79 | (draw-scoreboard-row gc 1 image-size label-font *score-label* value-font (model-score)) 80 | (draw-scoreboard-row gc 0 image-size label-font *level-label* value-font (model-level)) 81 | (draw-scoreboard-row gc 2 image-size label-font *points-needed-label* value-font (game-points-needed))) 82 | (gfs:dispose gc)))) 83 | 84 | (defclass scoreboard-panel (gfw:panel) ()) 85 | 86 | (defmethod gfw:preferred-size ((self scoreboard-panel) width-hint height-hint) 87 | (declare (ignore width-hint height-hint)) 88 | (let ((size (gfg:size (image-buffer-of (gfw:dispatcher self))))) 89 | (gfs:make-size :width (+ (gfs:size-width size) 2) :height (+ (gfs:size-height size) 2)))) 90 | -------------------------------------------------------------------------------- /graphic-forms-uitoolkit.asd: -------------------------------------------------------------------------------- 1 | (defsystem graphic-forms-uitoolkit 2 | :description "Graphic-Forms UI Toolkit" 3 | :depends-on ("cffi" 4 | "lw-compat" 5 | "closer-mop" 6 | "com.gigamonkeys.macro-utilities" 7 | "com.gigamonkeys.binary-data") 8 | :components 9 | ((:file "config") 10 | (:module "src" 11 | :depends-on ("config") 12 | :components 13 | ((:file "packages") 14 | (:module "uitoolkit" 15 | :depends-on ("packages") 16 | :components 17 | ((:module "system" 18 | :serial t 19 | :components 20 | (#+sbcl 21 | (:file "sbcl-callback-hacking") 22 | (:file "system-constants") 23 | (:file "system-classes") 24 | (:file "system-conditions") ; not a very good place 25 | (:file "system-generics") 26 | (:file "system-types") 27 | (:file "datastructs") 28 | (:file "clib") 29 | (:file "comctl32") 30 | (:file "comdlg32") 31 | (:file "shell32") 32 | (:file "gdi32") 33 | (:file "kernel32") 34 | (:file "user32") 35 | (:file "native-object") 36 | (:file "system-utils") 37 | (:file "metrics"))) 38 | (:module "graphics" 39 | :depends-on ("system") 40 | :components 41 | ((:file "graphics-constants") 42 | (:file "graphics-classes") 43 | (:file "graphics-generics") 44 | (:file "color" 45 | :depends-on ("graphics-classes")) 46 | (:file "palette" 47 | :depends-on ("graphics-classes")) 48 | (:file "image-data" 49 | :depends-on ("graphics-classes")) 50 | (:file "image" 51 | :depends-on ("graphics-classes" "graphics-generics")) 52 | (:file "icon-bundle" 53 | :depends-on ("graphics-constants" "image")) 54 | (:file "cursor" 55 | :depends-on ("graphics-classes" "image")) 56 | (:file "font-data") 57 | (:file "font") 58 | (:file "graphics-context") 59 | (:module "plugins" 60 | :components 61 | ((:file "graphics-plugin-packages") 62 | #-skip-default-plugin (:module "default" 63 | :serial t 64 | :components 65 | ((:file "file-formats") 66 | (:file "default-data-plugin"))) 67 | #+load-imagemagick-plugin (:module "imagemagick" 68 | :serial t 69 | :components 70 | ((:file "magick-core-types") 71 | (:file "magick-core-api") 72 | (:file "magick-data-plugin" 73 | :depends-on ("magick-core-types" "magick-core-api")))))))) 74 | (:module "widgets" 75 | :depends-on ("graphics") 76 | :serial t 77 | :components 78 | ((:file "widget-constants") 79 | (:file "widget-classes") 80 | (:file "layout-classes") 81 | (:file "thread-context") ; require defun in top-level.lisp 82 | (:file "message-generics") 83 | (:file "event-generics") 84 | (:file "layout-generics") 85 | (:file "widget-generics") 86 | (:file "display") 87 | (:file "event-source") 88 | (:file "widget-utils") 89 | (:file "timer") 90 | (:file "item") 91 | (:file "widget") 92 | (:file "color-dialog") 93 | (:file "file-dialog") 94 | (:file "font-dialog") 95 | (:file "control") ; require append-layout-item, subclass-wndproc 96 | (:file "edit") 97 | (:file "label") 98 | (:file "button") 99 | (:file "item-manager") 100 | (:file "list-item") ; require lb-select-item lb-deselect-item 101 | (:file "list-box") 102 | (:file "menu") 103 | (:file "menu-item") 104 | (:file "defmenu") 105 | (:file "progress-bar") 106 | (:file "event") ; require set-window-origin 107 | (:file "scrolling-helper") ; require obtain-top-child 108 | (:file "scrollbar") 109 | (:file "slider") 110 | (:file "status-bar") 111 | (:file "window") ; require arrang-hwnds 112 | (:file "root-window") 113 | (:file "top-level") 114 | (:file "panel") 115 | (:file "dialog") 116 | (:file "layout") 117 | (:file "border-layout") 118 | (:file "heap-layout") 119 | (:file "flow-layout") 120 | (:file "defwindow"))))))))) 121 | 122 | (defmethod perform :after ((op load-op) (c (eql (find-system :graphic-forms-uitoolkit)))) 123 | (pushnew :graphic-forms *features*)) 124 | -------------------------------------------------------------------------------- /src/uitoolkit/graphics/plugins/default/file-formats.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.graphics.default) 2 | 3 | (eval-when (:compile-toplevel :load-toplevel :execute) 4 | (use-package :com.gigamonkeys.binary-data)) 5 | 6 | ;;; 7 | ;;; fundamental binary types used by image definitions 8 | ;;; 9 | 10 | ;; This utility was copied from Peter Seibel's id3v2 package, 11 | ;; renamed to signify that it is for big-endian values. 12 | ;; 13 | (define-binary-type unsigned-integer-be (bytes bits-per-byte) 14 | (:reader (in) 15 | (loop with value = 0 16 | for low-bit downfrom (* bits-per-byte (1- bytes)) to 0 by bits-per-byte do 17 | (setf (ldb (byte bits-per-byte low-bit) value) (read-byte in)) 18 | finally (return value))) 19 | (:writer (out value) 20 | (loop for low-bit downfrom (* bits-per-byte (1- bytes)) to 0 by bits-per-byte 21 | do (write-byte (ldb (byte bits-per-byte low-bit) value) out)))) 22 | 23 | ;; This utility is based on the same unsigned-integer binary type, 24 | ;; but this one is for little-endian types. 25 | ;; 26 | (define-binary-type unsigned-integer-le (bytes bits-per-byte) 27 | (:reader (in) 28 | (loop with value = 0 29 | for low-bit from 0 to (* bits-per-byte (1- bytes)) by bits-per-byte do 30 | (setf (ldb (byte bits-per-byte low-bit) value) (read-byte in)) 31 | finally (return value))) 32 | (:writer (out value) 33 | (loop for low-bit from 0 to (* bits-per-byte (1- bytes)) by bits-per-byte 34 | do (write-byte (ldb (byte bits-per-byte low-bit) value) out)))) 35 | 36 | ;;; aliases for single-byte and 32-bit types with names 37 | ;;; matching the GDI docs 38 | ;;; 39 | (define-binary-type BYTE () (unsigned-integer-le :bytes 1 :bits-per-byte 8)) 40 | (define-binary-type DWORD () (unsigned-integer-le :bytes 4 :bits-per-byte 8)) 41 | (define-binary-type FXPT2DOT30 () (unsigned-integer-le :bytes 4 :bits-per-byte 8)) 42 | (define-binary-type LONG () (unsigned-integer-le :bytes 4 :bits-per-byte 8)) 43 | (define-binary-type WORD () (unsigned-integer-le :bytes 2 :bits-per-byte 8)) 44 | 45 | ;;; 46 | ;;; Win32 GDI Bitmap Formats 47 | ;;; 48 | 49 | (define-binary-class BITMAPFILEHEADER () 50 | ((bfType WORD) 51 | (bfSize DWORD) 52 | (bfReserved1 WORD) 53 | (bfReserved2 WORD) 54 | (bfOffBits DWORD))) 55 | 56 | (define-binary-class CIEXYZ () 57 | ((ciexyzX FXPT2DOT30) 58 | (ciexyzY FXPT2DOT30) 59 | (ciexyzZ FXPT2DOT30))) 60 | 61 | (define-binary-class CIEXYZTRIPLE () 62 | ((ciexyzRed CIEXYZ) 63 | (ciexyzGreen CIEXYZ) 64 | (ciexyzBlue CIEXYZ))) 65 | 66 | (define-tagged-binary-class BASE-BITMAPINFOHEADER () 67 | ((biSize DWORD) 68 | (biWidth LONG) 69 | (biHeight LONG) 70 | (biPlanes WORD) 71 | (biBitCount WORD) 72 | (biCompression DWORD) 73 | (biSizeImage DWORD) 74 | (biXPelsPerMeter LONG) 75 | (biYPelsPerMeter LONG) 76 | (biClrUsed DWORD) 77 | (biClrImportant DWORD)) 78 | (:dispatch 79 | (ecase biSize 80 | (40 'BITMAPINFOHEADER) 81 | (120 'BITMAPV4HEADER) 82 | (124 'BITMAPV5HEADER)))) 83 | 84 | (define-binary-class BITMAPINFOHEADER (BASE-BITMAPINFOHEADER) ()) 85 | 86 | (define-binary-class BITMAPV4HEADER (BASE-BITMAPINFOHEADER) 87 | ((bv4RedMask DWORD) 88 | (bv4GreenMask DWORD) 89 | (bv4BlueMask DWORD) 90 | (bv4AlphaMask DWORD) 91 | (bv4CSType DWORD) 92 | (bv4Endpoints CIEXYZTRIPLE) 93 | (bv4GammaRed DWORD) 94 | (bv4GammaGreen DWORD) 95 | (bv4GammaBlue DWORD))) 96 | 97 | (define-binary-class BITMAPV5HEADER (BITMAPV4HEADER) 98 | ((bv5Intent DWORD) 99 | (bv5ProfileData DWORD) 100 | (bv5ProfileSize DWORD) 101 | (bv5Reserved DWORD))) 102 | 103 | (define-binary-class RGBQUAD () 104 | ((rgbBlue BYTE) 105 | (rgbGreen BYTE) 106 | (rgbRed BYTE) 107 | (rgbReserved BYTE))) 108 | 109 | ;;; 110 | ;;; Win32 GDI Icon Formats 111 | ;;; 112 | 113 | (define-binary-class ICONDIR () 114 | ((idReserved WORD) 115 | (idType WORD) 116 | (idCount WORD))) ; ICONDIRENTRY array read separately 117 | 118 | (define-binary-class ICONDIRENTRY () 119 | ((ideWidth BYTE) 120 | (ideHeight BYTE) 121 | (ideColorCount BYTE) 122 | (ideReserved BYTE) 123 | (idePlanes WORD) 124 | (ideBitCount WORD) 125 | (ideBytesInRes DWORD) 126 | (ideImageOffset DWORD))) 127 | -------------------------------------------------------------------------------- /src/tests/uitoolkit/scroll-grid-panel.lisp: -------------------------------------------------------------------------------- 1 | (in-package #:graphic-forms.uitoolkit.tests) 2 | 3 | (defconstant +grid-cell-extent+ 50) 4 | (defconstant +grid-half-extent+ 25) 5 | 6 | (defvar *grid-model-size* (gfs:make-size :width 15 :height 10)) ; grid cells 7 | 8 | (defvar *grid-char-size* (gfs:make-size)) 9 | 10 | (defclass scroll-grid-panel-events (gfw:event-dispatcher) ()) 11 | 12 | (defun select-grid (disp item) 13 | (declare (ignore disp item))) 14 | 15 | (defun make-scroll-grid-panel (parent) 16 | (setf *default-pathname-defaults* (merge-pathnames "uitoolkit/" *gf-tests-dir*)) 17 | (let ((panel-size (gfs:make-size :width (1+ (* (gfs:size-width *grid-model-size*) +grid-cell-extent+)) 18 | :height (1+ (* (gfs:size-height *grid-model-size*) +grid-cell-extent+)))) 19 | (panel (make-instance 'gfw:panel :dispatcher (make-instance 'scroll-grid-panel-events) 20 | :parent parent))) 21 | (setf (gfw:maximum-size panel) panel-size 22 | (gfw:minimum-size panel) panel-size) 23 | (assert (gfs:equal-size-p panel-size (slot-value panel 'gfw::max-size))) 24 | (setf (gfs:size-width *grid-char-size*) (floor +grid-half-extent+ 2) 25 | (gfs:size-height *grid-char-size*) (floor +grid-half-extent+ 2)) 26 | (setf (gfw:cursor-of panel) 27 | (make-instance 'gfg:cursor 28 | :file (merge-pathnames "custom.cur"))) 29 | panel)) 30 | 31 | (defun set-grid-scroll-params (window) 32 | (let* ((disp (gfw:dispatcher window)) 33 | (panel (gfw::obtain-top-child window)) 34 | (panel-size (gfw:size panel)) 35 | (scrollbar (gfw:obtain-horizontal-scrollbar window))) 36 | (setf (gfw:outer-limit scrollbar) (gfs:size-width panel-size)) 37 | (setf (gfw:thumb-position scrollbar) 0) 38 | (setf scrollbar (gfw:obtain-vertical-scrollbar window)) 39 | (setf (gfw:outer-limit scrollbar) (gfs:size-height panel-size)) 40 | (setf (gfw:thumb-position scrollbar) 0) 41 | (setf (gfw:step-increments disp) (gfs:make-size :width 1 :height 1)) 42 | (setf (slot-value disp 'gfw::viewport-origin) (gfs:make-point)) 43 | (gfw:event-resize disp window (gfw:size window) :restored))) 44 | 45 | (defmethod gfw:event-paint ((disp scroll-grid-panel-events) window gc rect) 46 | (declare (ignore window)) 47 | (gfg:clear gc gfg:*color-button-face*) 48 | (setf (gfg:foreground-color gc) gfg:*color-black* 49 | (gfg:pen-style gc) '(:solid :flat-endcap)) 50 | (let* ((pnt (gfs:location rect)) 51 | (size (gfs:size rect)) 52 | (first-row (floor (gfs:point-y pnt) +grid-cell-extent+)) 53 | (last-row (floor (+ (gfs:point-y pnt) (gfs:size-height size)) +grid-cell-extent+)) 54 | (first-col (floor (gfs:point-x pnt) +grid-cell-extent+)) 55 | (last-col (floor (+ (gfs:point-x pnt) (gfs:size-width size)) +grid-cell-extent+)) 56 | (lr-pnt (gfs:make-point :x (* +grid-cell-extent+ (gfs:size-width *grid-model-size*)) 57 | :y (* +grid-cell-extent+ (gfs:size-height *grid-model-size*))))) 58 | (loop for row from first-row upto last-row 59 | for start-pnt = (gfs:make-point :y (* row +grid-cell-extent+)) 60 | do (progn 61 | (gfg:draw-line gc start-pnt (gfs:make-point :x (gfs:point-x lr-pnt) 62 | :y (gfs:point-y start-pnt))) 63 | (loop for col from first-col upto last-col 64 | for text = (format nil "~d ~d" col row) 65 | for start-pnt = (gfs:make-point :x (* col +grid-cell-extent+)) 66 | for text-pnt = (gfs:make-point :x (+ (* col +grid-cell-extent+) 67 | (- +grid-half-extent+ 68 | (gfs:size-width *grid-char-size*))) 69 | :y (+ (* row +grid-cell-extent+) 70 | (- +grid-half-extent+ 71 | (gfs:size-height *grid-char-size*)))) 72 | do (progn 73 | (if (= row first-row) 74 | (gfg:draw-line gc start-pnt (gfs:make-point :x (gfs:point-x start-pnt) 75 | :y (gfs:point-y lr-pnt)))) 76 | (gfg:draw-text gc text text-pnt '(:transparent)))))))) 77 | -------------------------------------------------------------------------------- /src/demos/unblocked/tiles-panel.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.tests) 2 | 3 | (defvar *unblocked-dir* (merge-pathnames "src/demos/unblocked/" *gf-dir*)) 4 | 5 | (eval-when (:compile-toplevel :load-toplevel :execute) 6 | (defconstant +tile-bmp-width+ 24) 7 | (defconstant +tile-bmp-height+ 24)) 8 | 9 | (defun tiles->window (pnt) 10 | (let ((xpos (1+ (* (gfs:point-x pnt) +tile-bmp-width+))) 11 | (ypos (1+ (* (- (1- +vert-tile-count+) (gfs:point-y pnt)) +tile-bmp-height+))) 12 | (size (gfw:client-size (get-tiles-panel)))) 13 | (if (or (>= xpos (gfs:size-width size)) (>= ypos (gfs:size-height size))) 14 | nil 15 | (gfs:make-point :x xpos :y ypos)))) 16 | 17 | (defun window->tiles (pnt) 18 | (let ((xpos (floor (1- (gfs:point-x pnt)) +tile-bmp-width+)) 19 | (ypos (- +vert-tile-count+ (1+ (floor (1- (gfs:point-y pnt)) +tile-bmp-height+))))) 20 | (if (or (>= xpos +horz-tile-count+) (>= ypos +vert-tile-count+)) 21 | nil 22 | (gfs:make-point :x xpos :y ypos)))) 23 | 24 | (defclass tiles-panel-events (double-buffered-event-dispatcher) 25 | ((tile-image-table 26 | :accessor tile-image-table-of 27 | :initform (make-hash-table :test #'equal)) 28 | (shape-kind 29 | :accessor shape-kind-of 30 | :initform 0) 31 | (shape-pnts 32 | :accessor shape-pnts-of 33 | :initform nil))) 34 | 35 | (defun draw-tiles-directly (panel shape-pnts kind) 36 | (gfw:with-graphics-context (gc panel) 37 | (let ((image-table (tile-image-table-of (gfw:dispatcher panel)))) 38 | (loop for pnt in shape-pnts 39 | do (let ((image (gethash kind image-table))) 40 | (gfg:draw-image gc image (tiles->window pnt))))))) 41 | 42 | (defmethod dispose ((self tiles-panel-events)) 43 | (let ((table (tile-image-table-of self))) 44 | (maphash #'(lambda (kind image) 45 | (declare (ignore kind)) 46 | (gfs:dispose image)) 47 | table)) 48 | (setf (tile-image-table-of self) nil) 49 | (setf (shape-pnts-of self) nil) 50 | (call-next-method)) 51 | 52 | (defmethod initialize-instance :after ((self tiles-panel-events) &key buffer-size) 53 | (declare (ignorable buffer-size)) 54 | (let ((*default-pathname-defaults* (parse-namestring *unblocked-dir*)) 55 | (table (tile-image-table-of self)) 56 | (kind 1)) 57 | (loop for filename in '("blue-tile.bmp" "brown-tile.bmp" "red-tile.bmp" 58 | "green-tile.bmp" "pink-tile.bmp" "gold-tile.bmp") 59 | do (let ((image (make-instance 'gfg:image))) 60 | (gfg:load image (merge-pathnames filename)) 61 | (setf (gethash kind table) image) 62 | (incf kind))))) 63 | 64 | (defmethod gfw:event-mouse-down ((self tiles-panel-events) panel point button) 65 | (multiple-value-bind (shape-kind shape-pnts) 66 | (ctrl-start-selection (shape-pnts-of self) panel point button) 67 | (if shape-pnts 68 | (progn 69 | (setf (shape-kind-of self) shape-kind 70 | (shape-pnts-of self) shape-pnts) 71 | (gfw:capture-mouse panel)) 72 | (progn 73 | (draw-tiles-directly panel (shape-pnts-of self) (shape-kind-of self)) 74 | (setf (shape-kind-of self) 0) 75 | (setf (shape-pnts-of self) nil))))) 76 | 77 | (defmethod gfw:event-mouse-up ((self tiles-panel-events) panel point button) 78 | (gfw:release-mouse) 79 | (ctrl-finish-selection (shape-pnts-of self) (shape-kind-of self) panel point button) 80 | (setf (shape-kind-of self) 0) 81 | (setf (shape-pnts-of self) nil)) 82 | 83 | (defmethod update-buffer ((self tiles-panel-events)) 84 | (gfw:with-graphics-context (gc (image-buffer-of self)) 85 | (let ((image-table (tile-image-table-of self))) 86 | (clear-buffer self gc) 87 | (map-tiles #'(lambda (pnt kind) 88 | (unless (= kind 0) 89 | (gfg:draw-image gc (gethash kind image-table) (tiles->window pnt)))) 90 | (model-tiles))))) 91 | 92 | (defclass tiles-panel (gfw:panel) ()) 93 | 94 | (defmethod gfs:dispose ((self tiles-panel)) 95 | (dispose (gfw:dispatcher self)) 96 | (call-next-method)) 97 | 98 | (defmethod gfw:preferred-size ((self tiles-panel) width-hint height-hint) 99 | (declare (ignore width-hint height-hint)) 100 | (let ((size (gfg:size (image-buffer-of (gfw:dispatcher self))))) 101 | (gfs:make-size :width (+ (gfs:size-width size) 2) :height (+ (gfs:size-height size) 2)))) 102 | -------------------------------------------------------------------------------- /src/tests/uitoolkit/border-layout-unit-tests.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.tests) 2 | 3 | (defvar *all-border-kids* (list (make-instance 'mock-widget :min-size *child-size-1*) ; top 4 | (make-instance 'mock-widget :min-size *child-size-2*) ; right 5 | (make-instance 'mock-widget :min-size *child-size-1*) ; bottom 6 | (make-instance 'mock-widget :min-size *child-size-2*) ; left 7 | (make-instance 'mock-widget :min-size *child-size-3*))) ; center 8 | 9 | (defvar *outer-border-kids* (list (make-instance 'mock-widget :min-size *child-size-1*) ; top 10 | (make-instance 'mock-widget :min-size *child-size-2*) ; right 11 | (make-instance 'mock-widget :min-size *child-size-1*) ; bottom 12 | (make-instance 'mock-widget :min-size *child-size-2*) ; left 13 | nil)) 14 | 15 | (defvar *top-right-border-kids* (list (make-instance 'mock-widget :min-size *child-size-1*) ; top 16 | (make-instance 'mock-widget :min-size *child-size-2*) ; right 17 | nil nil nil)) 18 | 19 | (defvar *top-bottom-border-kids* (list (make-instance 'mock-widget :min-size *child-size-1*) ; top 20 | nil 21 | (make-instance 'mock-widget :min-size *child-size-1*) ; bottom 22 | nil nil)) 23 | 24 | (defvar *center-border-kid* (list nil nil nil nil 25 | (make-instance 'mock-widget :min-size *child-size-3*))) 26 | 27 | ;;; 28 | ;;; NOTE: the rects to be validated in each test must be specified in the 29 | ;;; the following order: center, top, left, bottom, right 30 | ;;; 31 | 32 | (define-layout-test border-layout-test1 33 | -1 -1 80 50 34 | nil 35 | '((20 5 40 40) (0 0 80 5) (0 5 20 40) (0 45 80 5) (60 5 20 40)) 36 | #'make-border-layout *all-border-kids*) 37 | 38 | (define-layout-test border-layout-test2 39 | -1 -1 40 20 40 | nil 41 | '((0 0 40 5) (0 5 20 10) (0 15 40 5) (20 5 20 10)) 42 | #'make-border-layout *outer-border-kids*) 43 | 44 | (define-layout-test border-layout-test3 45 | -1 -1 40 40 46 | nil 47 | '((0 0 40 40)) 48 | #'make-border-layout *center-border-kid*) 49 | 50 | (define-layout-test border-layout-test4 51 | -1 -1 25 15 52 | nil 53 | '((0 0 25 5) (0 5 20 10)) 54 | #'make-border-layout *top-right-border-kids*) 55 | 56 | (define-layout-test border-layout-test5 57 | -1 -1 25 10 58 | nil 59 | '((0 0 25 5) (0 5 25 5)) 60 | #'make-border-layout *top-bottom-border-kids*) 61 | 62 | (define-layout-test border-layout-test6 63 | 26 -1 26 50 64 | nil 65 | '((6 5 13 40) (0 0 26 5) (0 5 6 40) (0 45 26 5) (19 5 6 40)) 66 | #'make-border-layout *all-border-kids*) 67 | 68 | (define-layout-test border-layout-test7 69 | -1 -1 90 58 70 | nil 71 | '((24 8 40 40) (4 3 80 5) (4 8 20 40) (4 48 80 5) (64 8 20 40)) 72 | #'make-border-layout *all-border-kids* 4 3 6 5) 73 | 74 | (defun border-layout-spacing (layout) 75 | (loop for pair in (gfw::data-of layout) 76 | for widget = (first pair) 77 | for key = (first (second pair)) 78 | do (case key 79 | ;; note - we leave :center region with default spacing 80 | (:top (setf (gfw:layout-attribute layout widget :leading-spacing) 2)) 81 | (:left (setf (gfw:layout-attribute layout widget :trailing-spacing) 3)) 82 | (:right (setf (gfw:layout-attribute layout widget :spacing) 4)) 83 | (:bottom (setf (gfw:layout-attribute layout widget :center-spacing) 5))))) 84 | 85 | (define-layout-test border-layout-test8 86 | -1 -1 80 50 87 | #'border-layout-spacing 88 | '((20 5 40 40) (0 0 80 5) (0 5 20 40) (0 45 80 5) (60 5 20 40)) 89 | #'make-border-layout *all-border-kids*) 90 | -------------------------------------------------------------------------------- /src/uitoolkit/graphics/graphics-classes.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.graphics) 2 | 3 | (eval-when (:compile-toplevel :load-toplevel :execute) 4 | (defstruct color 5 | (red 0) 6 | (green 0) 7 | (blue 0)) 8 | 9 | (defstruct font-data 10 | (char-set 0) 11 | (face-name "") 12 | (point-size 10) 13 | (style nil)) 14 | 15 | (defstruct font-metrics 16 | (ascent 0) 17 | (descent 0) 18 | (leading 0) 19 | (avg-char-width 0) 20 | (max-char-width 0)) 21 | 22 | (defmacro ascent (metrics) 23 | `(gfg::font-metrics-ascent ,metrics)) 24 | 25 | (defmacro descent (metrics) 26 | `(gfg::font-metrics-descent ,metrics)) 27 | 28 | (defmacro leading (metrics) 29 | `(gfg::font-metrics-leading ,metrics)) 30 | 31 | (defmacro height (metrics) 32 | (let ((tmp-metrics (gensym))) 33 | `(let ((,tmp-metrics ,metrics)) 34 | (+ (gfg::font-metrics-ascent ,tmp-metrics) 35 | (gfg::font-metrics-descent ,tmp-metrics))))) 36 | 37 | (defmacro average-char-width (metrics) 38 | `(gfg::font-metrics-avg-char-width ,metrics)) 39 | 40 | (defmacro maximum-char-width (metrics) 41 | `(gfg::font-metrics-max-char-width ,metrics)) 42 | 43 | (defstruct palette 44 | (red-mask 0) 45 | (green-mask 0) 46 | (blue-mask 0) 47 | (red-shift 0) 48 | (green-shift 0) 49 | (blue-shift 0) 50 | (direct nil) 51 | (table nil)) ; vector of COLOR structs 52 | 53 | (defmacro color-table (data) 54 | `(gfg::palette-table ,data))) 55 | 56 | (defclass cursor (gfs:native-object) 57 | ((shared 58 | :reader sharedp 59 | :initarg :shared 60 | :initform nil)) 61 | (:documentation "This class wraps a native cursor handle.")) 62 | 63 | (defclass image-data-plugin (gfs:native-object) () 64 | (:documentation "Base class for image data plugin implementations.")) 65 | 66 | (defclass image-data () 67 | ((data-plugin 68 | :reader data-plugin-of 69 | :initarg :data-plugin 70 | :initform nil)) 71 | (:documentation "This class maintains image attributes, color, and pixel data.")) 72 | 73 | (defclass font (gfs:native-object) () 74 | (:documentation "This class wraps a native font handle.")) 75 | 76 | (defclass graphics-context (gfs:native-object) 77 | ((dc-destructor 78 | :accessor dc-destructor-of 79 | :initform nil) 80 | (widget-handle 81 | :accessor widget-handle-of 82 | :initform nil) 83 | (surface-size 84 | :accessor surface-size-of 85 | :initarg :surface-size 86 | :initform nil) 87 | (logbrush-style 88 | :accessor logbrush-style-of 89 | :initform gfs::+bs-solid+) 90 | (logbrush-color 91 | :accessor logbrush-color-of 92 | :initform 0) 93 | (logbrush-hatch 94 | :accessor logbrush-hatch-of 95 | :initform gfs::+hs-bdiagonal+) 96 | (miter-limit 97 | :accessor miter-limit 98 | :initform 10.0) 99 | (pen-style 100 | :accessor pen-style 101 | :initform '(:solid)) 102 | (pen-width 103 | :accessor pen-width 104 | :initform 1) 105 | (pen-handle 106 | :accessor pen-handle-of 107 | :initform (cffi:null-pointer))) 108 | (:documentation "This class represents the context associated with drawing primitives.")) 109 | 110 | (defclass icon-bundle (gfs:native-object) () 111 | (:documentation "This class encapsulates a set of Win32 icon handles.")) 112 | 113 | (defclass image (gfs:native-object) 114 | ((transparency-pixel 115 | :accessor transparency-pixel-of 116 | :initarg :transparency-pixel 117 | :initform nil)) 118 | (:documentation "This class encapsulates a Win32 bitmap handle.")) 119 | 120 | (defmacro blue-mask (data) 121 | `(gfg::palette-blue-mask ,data)) 122 | 123 | (defmacro blue-shift (data) 124 | `(gfg::palette-blue-shift ,data)) 125 | 126 | (defmacro direct (data flag) 127 | `(setf (gfg::palette-direct ,data) ,flag)) 128 | 129 | (defmacro green-mask (data) 130 | `(gfg::palette-green-mask ,data)) 131 | 132 | (defmacro green-shift (data) 133 | `(gfg::palette-green-shift ,data)) 134 | 135 | (defmacro red-mask (data) 136 | `(gfg::palette-red-mask ,data)) 137 | 138 | (defmacro red-shift (data) 139 | `(gfg::palette-red-shift ,data)) 140 | 141 | (defclass pattern (gfs:native-object) () 142 | (:documentation "This class represents a pattern to be used with a brush.")) 143 | 144 | (defclass transform (gfs:native-object) () 145 | (:documentation "This class specifies how coordinates are transformed.")) 146 | -------------------------------------------------------------------------------- /src/uitoolkit/widgets/color-dialog.lisp: -------------------------------------------------------------------------------- 1 | (in-package #:graphic-forms.uitoolkit.widgets) 2 | 3 | (eval-when (:compile-toplevel :load-toplevel :execute) 4 | (defconstant +custom-color-array-size+ 16)) 5 | 6 | ;;; 7 | ;;; helper functions 8 | ;;; 9 | 10 | (defun obtain-chosen-color (dlg) 11 | (let ((cc-ptr (gfs:handle dlg))) 12 | (if (cffi:null-pointer-p cc-ptr) 13 | (error 'gfs:disposed-error)) 14 | (cffi:with-foreign-slots ((gfs::result gfs::ccolors) cc-ptr (:struct gfs::choosecolor)) 15 | (values (gfg:rgb->color gfs::result) 16 | (loop for index to (1- +custom-color-array-size+) 17 | collect (gfg:rgb->color (cffi:mem-aref gfs::ccolors 'gfs::colorref index))))))) 18 | 19 | (defmacro with-color-dialog ((owner style color custom-colors &key initial-color initial-custom-colors) &body body) 20 | (let ((dlg (gensym))) 21 | `(let ((,color nil) 22 | (,custom-colors nil) 23 | (,dlg (make-instance 'color-dialog 24 | :initial-custom-colors ,initial-custom-colors 25 | :initial-color ,initial-color 26 | :owner ,owner 27 | :style ,style))) 28 | (unwind-protect 29 | (unless (zerop (show ,dlg t)) 30 | (multiple-value-bind (tmp-color tmp-custom) 31 | (obtain-chosen-color ,dlg) 32 | (setf ,color tmp-color 33 | ,custom-colors tmp-custom) 34 | ,@body)) 35 | (gfs:dispose ,dlg))))) 36 | 37 | ;;; 38 | ;;; methods 39 | ;;; 40 | 41 | (defmethod compute-style-flags ((self color-dialog) &rest extra-data) 42 | (let ((std-flags (logior gfs::+cc-anycolor+ gfs::+cc-preventfullopen+ (if extra-data gfs::+cc-rgbinit+ 0)))) 43 | (loop for sym in (style-of self) 44 | do (ecase sym 45 | (:allow-custom-colors 46 | (setf std-flags (logand std-flags (lognot gfs::+cc-preventfullopen+)))) 47 | (:display-solid-only) 48 | (setf std-flags (logior std-flags gfs::+cc-solidcolor+)))) 49 | (values std-flags 0))) 50 | 51 | (defmethod gfs:dispose ((self color-dialog)) 52 | (let ((cc-ptr (gfs:handle self))) 53 | (unless (cffi:null-pointer-p cc-ptr) 54 | (cffi:with-foreign-slots ((gfs::ccolors) cc-ptr (:struct gfs::choosecolor)) 55 | (unless (cffi:null-pointer-p gfs::ccolors) 56 | (cffi:foreign-free gfs::ccolors))) 57 | (cffi:foreign-free cc-ptr) 58 | (setf (slot-value self 'gfs:handle) nil)))) 59 | 60 | (defmethod initialize-instance :after ((self color-dialog) &key initial-color initial-custom-colors owner &allow-other-keys) 61 | (if (null owner) 62 | (error 'gfs:toolkit-error :detail ":owner initarg is required")) 63 | (if (gfs:disposed-p owner) 64 | (error 'gfs:disposed-error)) 65 | (let ((cc-ptr (cffi:foreign-alloc '(:struct gfs::choosecolor))) 66 | (colors-ptr (cffi:foreign-alloc 'gfs::colorref :count +custom-color-array-size+)) 67 | (index 0) 68 | (default-rgb (gfg:color->rgb gfg:*color-black*))) 69 | (loop for color in initial-custom-colors 70 | when (< index +custom-color-array-size+) 71 | do (progn 72 | (setf (cffi:mem-aref colors-ptr 'gfs::colorref index) (gfg:color->rgb color)) 73 | (incf index))) 74 | (loop until (>= index +custom-color-array-size+) 75 | do (progn 76 | (setf (cffi:mem-aref colors-ptr 'gfs::colorref index) default-rgb) 77 | (incf index))) 78 | (multiple-value-bind (std-style ex-style) 79 | (compute-style-flags self initial-color) 80 | (declare (ignore ex-style)) 81 | (cffi:with-foreign-slots ((gfs::ccsize gfs::howner gfs::hinst gfs::result 82 | gfs::ccolors gfs::flags gfs::cdata gfs::hookfn gfs::templname) 83 | cc-ptr (:struct gfs::choosecolor)) 84 | (setf gfs::ccsize (cffi:foreign-type-size '(:struct gfs::choosecolor)) 85 | gfs::howner (gfs:handle owner) 86 | gfs::hinst (cffi:null-pointer) 87 | gfs::result (gfg:color->rgb (or initial-color (gfg:make-color))) 88 | gfs::ccolors colors-ptr 89 | gfs::flags std-style 90 | gfs::cdata 0 91 | gfs::hookfn (cffi:null-pointer) 92 | gfs::templname (cffi:null-pointer)))) 93 | (setf (slot-value self 'gfs:handle) cc-ptr))) 94 | 95 | (defmethod show ((self color-dialog) flag) 96 | (declare (ignore flag)) 97 | (show-common-dialog self #'gfs::choose-color)) 98 | -------------------------------------------------------------------------------- /src/uitoolkit/widgets/button.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.widgets) 2 | 3 | (defconstant +horizontal-button-text-margin+ 7) 4 | (defconstant +vertical-button-text-margin+ 5) 5 | 6 | ;;; 7 | ;;; methods 8 | ;;; 9 | 10 | (defmethod check ((self button) flag) 11 | (let ((bits (if flag gfs::+bst-checked+ gfs::+bst-unchecked+))) 12 | (gfs::send-message (gfs:handle self) gfs::+bm-setcheck+ bits 0))) 13 | 14 | (defmethod checked-p ((self button)) 15 | (let ((bits (gfs::send-message (gfs:handle self) gfs::+bm-getcheck+ 0 0))) 16 | (= (logand bits gfs::+bst-checked+) gfs::+bst-checked+))) 17 | 18 | (defmethod compute-style-flags ((self button) &rest extra-data) 19 | (declare (ignore extra-data)) 20 | (let ((std-flags +default-child-style+) 21 | (style (style-of self))) 22 | (loop for sym in style 23 | do (cond 24 | ;; primary button styles 25 | ;; 26 | ((eq sym :check-box) 27 | (setf std-flags (logior std-flags gfs::+bs-autocheckbox+))) 28 | ((eq sym :default-button) 29 | (setf std-flags (logior std-flags gfs::+bs-defpushbutton+))) 30 | ((or (eq sym :push-button) (eq sym :cancel-button)) 31 | (setf std-flags (logior std-flags gfs::+bs-pushbutton+))) 32 | ((eq sym :radio-button) 33 | (setf std-flags (logior std-flags gfs::+bs-autoradiobutton+))) 34 | ((eq sym :toggle-button) 35 | (setf std-flags (logior std-flags gfs::+bs-autocheckbox+ gfs::+bs-pushlike+))) 36 | ((eq sym :tri-state) 37 | (setf std-flags (logior std-flags gfs::+bs-auto3state+))))) 38 | (if (null style) 39 | (logior std-flags gfs::+bs-pushbutton+)) 40 | (values std-flags 0))) 41 | 42 | (defmethod initialize-instance :after ((self button) &key parent text &allow-other-keys) 43 | (let ((id (cond 44 | ((find :default-button (style-of self)) 45 | gfs::+idok+) 46 | ((find :cancel-button (style-of self)) 47 | gfs::+idcancel+) 48 | (t 49 | (increment-widget-id (thread-context)))))) 50 | (create-control self parent text gfs::+icc-standard-classes+ id) 51 | (if (test-native-style self gfs::+bs-defpushbutton+) 52 | (gfs::send-message (gfs:handle parent) 53 | gfs::+dm-setdefid+ 54 | (cffi:pointer-address (gfs:handle self)) 55 | 0)))) 56 | 57 | (defmethod preferred-size ((self button) width-hint height-hint) 58 | (let ((text-size (widget-text-size self #'text gfs::+dt-singleline+)) 59 | (size (gfs:make-size)) 60 | (b-width (* (border-width self) 2)) 61 | (need-cb-size (intersection '(:check-box :radio-button :tri-state) (style-of self))) 62 | (cb-size (check-box-size))) 63 | (cond 64 | ((>= width-hint 0) 65 | (setf (gfs:size-width size) width-hint)) 66 | (need-cb-size 67 | (setf (gfs:size-width size) (+ +horizontal-button-text-margin+ 68 | (gfs:size-width cb-size) 69 | (gfs:size-width text-size)))) 70 | (t 71 | (setf (gfs:size-width size) (+ b-width 72 | (* +horizontal-button-text-margin+ 2) 73 | (gfs:size-width text-size))))) 74 | (cond 75 | ((>= height-hint 0) 76 | (setf (gfs:size-height size) height-hint)) 77 | (need-cb-size 78 | (setf (gfs:size-height size) (+ (* +vertical-button-text-margin+ 2) 79 | (max (gfs:size-height text-size) 80 | (gfs:size-height cb-size))))) 81 | (t 82 | (setf (gfs:size-height size) (+ b-width 83 | (* +vertical-button-text-margin+ 2) 84 | (gfs:size-height text-size))))) 85 | size)) 86 | 87 | (defmethod select ((self button) flag) 88 | (check self flag)) 89 | 90 | (defmethod selected-p ((self button)) 91 | (checked-p self)) 92 | 93 | (defmethod text ((self button)) 94 | (get-widget-text self)) 95 | 96 | (defmethod (setf text) (str (self button)) 97 | (set-widget-text self str)) 98 | 99 | (defmethod text-baseline ((self button)) 100 | (widget-text-baseline self +vertical-button-text-margin+)) 101 | 102 | (defmethod update-native-style ((self button) flags) 103 | (gfs::send-message (gfs:handle self) gfs::+bm-setstyle+ flags 1) 104 | flags) 105 | -------------------------------------------------------------------------------- /src/tests/uitoolkit/scroll-text-panel.lisp: -------------------------------------------------------------------------------- 1 | (in-package #:graphic-forms.uitoolkit.tests) 2 | 3 | (defvar *text-to-draw* "ABCDEFGHIJKLMNOPQRSTUVWXYZ[]0123456789{}") 4 | 5 | (defvar *text-model-size* (gfs:make-size :width 100 :height 100)) ; character cells 6 | 7 | (defvar *text-panel-font-data* (gfg:make-font-data :face-name "Lucida Console" 8 | :point-size 10)) 9 | 10 | (defclass scroll-text-panel-events (gfw:event-dispatcher) 11 | ((font 12 | :accessor font-of 13 | :initform nil))) 14 | 15 | (defun draw-text-chunk (gc metrics row first-col last-col) 16 | (let* ((col-diff (1+ (- last-col first-col))) 17 | (text-len (length *text-to-draw*)) 18 | (text-start (mod first-col text-len)) 19 | (text-end (mod last-col text-len)) 20 | (ch-width (gfg:average-char-width metrics)) 21 | (ch-height (gfg:height metrics)) 22 | (pnt (gfs:make-point :x (* ch-width first-col) 23 | :y (* ch-height row)))) 24 | (cond 25 | ((and (<= col-diff text-len) (<= text-start text-end)) 26 | (gfg:draw-text gc (subseq *text-to-draw* text-start (1+ text-end)) pnt)) 27 | ((or (> col-diff text-len) (> text-start text-end)) 28 | (gfg:draw-text gc (subseq *text-to-draw* text-start text-len) pnt) 29 | (incf (gfs:point-x pnt) (* (- text-len text-start) ch-width)) 30 | (dotimes (i (floor col-diff text-len)) 31 | (gfg:draw-text gc *text-to-draw* pnt) 32 | (incf (gfs:point-x pnt) (* text-len ch-width))) 33 | (gfg:draw-text gc (subseq *text-to-draw* 0 (1+ text-end)) pnt))))) 34 | 35 | (defun make-scroll-text-panel (parent) 36 | (let* ((disp (make-instance 'scroll-text-panel-events)) 37 | (panel (make-instance 'gfw:panel :dispatcher disp :parent parent))) 38 | (gfw:with-graphics-context (gc panel) 39 | (let* ((metrics (gfg:metrics gc (font-of disp))) 40 | (panel-size (gfs:make-size :width (* (gfs:size-width *text-model-size*) 41 | (gfg:average-char-width metrics)) 42 | :height (* (gfs:size-height *text-model-size*) 43 | (gfg:height metrics))))) 44 | (setf (gfw:maximum-size panel) panel-size 45 | (gfw:minimum-size panel) panel-size))) 46 | panel)) 47 | 48 | (defun set-text-scroll-params (window) 49 | (let* ((disp (gfw:dispatcher window)) 50 | (panel (gfw::obtain-top-child window)) 51 | (panel-size (gfw:size panel))) 52 | (gfw:with-graphics-context (gc panel) 53 | (let ((metrics (gfg:metrics gc (font-of (gfw:dispatcher panel)))) 54 | (scrollbar (gfw:obtain-horizontal-scrollbar window))) 55 | (setf (gfw:outer-limit scrollbar) (gfs:size-width panel-size)) 56 | (setf (gfw:thumb-position scrollbar) 0) 57 | (setf scrollbar (gfw:obtain-vertical-scrollbar window)) 58 | (setf (gfw:outer-limit scrollbar) (gfs:size-height panel-size)) 59 | (setf (gfw:thumb-position scrollbar) 0) 60 | (setf (gfw:step-increments disp) (gfs:make-size :width (gfg:average-char-width metrics) 61 | :height (gfg:height metrics))))) 62 | (setf (slot-value disp 'gfw::viewport-origin) (gfs:make-point)) 63 | (gfw:event-resize disp window (gfw:size window) :restored))) 64 | 65 | (defmethod initialize-instance ((self scroll-text-panel-events) &key) 66 | (gfw:with-graphics-context (gc) 67 | (setf (font-of self) (make-instance 'gfg:font :gc gc :data *text-panel-font-data*)))) 68 | 69 | (defmethod gfw:event-dispose ((disp scroll-text-panel-events) (panel gfw:panel)) 70 | (let ((font (font-of disp))) 71 | (if font 72 | (gfs:dispose font)) 73 | (setf (font-of disp) nil))) 74 | 75 | (defmethod gfw:event-paint ((disp scroll-text-panel-events) window gc rect) 76 | (declare (ignore window)) 77 | (gfg:clear gc gfg:*color-white*) 78 | (setf (gfg:foreground-color gc) gfg:*color-black* 79 | (gfg:font gc) (font-of disp)) 80 | (let* ((metrics (gfg:metrics gc (font-of disp))) 81 | (pnt (gfs:location rect)) 82 | (size (gfs:size rect)) 83 | (first-row (floor (gfs:point-y pnt) (gfg:height metrics))) 84 | (last-row (floor (+ (gfs:point-y pnt) (gfs:size-height size)) (gfg:height metrics))) 85 | (first-col (floor (gfs:point-x pnt) (gfg:average-char-width metrics))) 86 | (last-col (floor (+ (gfs:point-x pnt) (gfs:size-width size)) (gfg:average-char-width metrics)))) 87 | (setf (gfs:point-x pnt) (* first-col (gfg:average-char-width metrics))) 88 | (loop for row from first-row upto last-row 89 | do (draw-text-chunk gc metrics row first-col last-col)))) 90 | 91 | -------------------------------------------------------------------------------- /src/uitoolkit/graphics/plugins/imagemagick/magick-data-plugin.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.graphics.imagemagick) 2 | 3 | (defclass magick-data-plugin (gfg:image-data-plugin) () 4 | (:documentation "ImageMagick library plugin for the graphics package.")) 5 | 6 | (defun loader (path) 7 | (unless *magick-initialized* 8 | (initialize-magick (cffi:null-pointer)) 9 | (setf *magick-initialized* t)) 10 | (if (gethash (string-downcase (pathname-type path)) gfg:*image-file-types*) 11 | (with-image-path ((if (typep path 'pathname) (namestring path) path) info ex) 12 | (let ((images-ptr (read-image info ex))) 13 | (if (not (eql (cffi:foreign-slot-value ex 'exception-info 'severity) :undefined)) 14 | (error 'gfs:toolkit-error :detail (format nil 15 | "exception reason: ~s" 16 | (cffi:foreign-slot-value ex 'exception-info 'reason)))) 17 | (loop for ptr = images-ptr then (get-next-image-in-list ptr) 18 | while (and ptr (not (gfs:null-handle-p ptr))) 19 | collect (make-instance 'magick-data-plugin :handle ptr)))) 20 | nil)) 21 | 22 | (push #'loader gfg::*image-plugins*) 23 | 24 | (defmethod gfg:depth ((self magick-data-plugin)) 25 | ;; FIXME: further debugging of non-true-color format required throughout 26 | ;; this plugin, reverting back to assumption of 32bpp for now. 27 | #| 28 | (let ((handle (gfs:handle self))) 29 | (if (null handle) 30 | (error 'gfs:disposed-error)) 31 | (cffi:foreign-slot-value handle 'magick-image 'depth))) 32 | |# 33 | 32) 34 | 35 | (defmethod gfs:dispose ((self magick-data-plugin)) 36 | (let ((victim (gfs:handle self))) 37 | (unless (or (null victim) (cffi:null-pointer-p victim)) 38 | (destroy-image victim))) 39 | (setf (slot-value self 'gfs:handle) nil)) 40 | 41 | (defmethod gfg:copy-pixels ((self magick-data-plugin) pixels-pointer) 42 | (let* ((handle (gfs:handle self)) 43 | (im-size (gfg:size self)) 44 | (pixel-count (* (gfs:size-width im-size) (gfs:size-height im-size))) 45 | (pix-tmp (get-image-pixels handle 0 0 (gfs:size-width im-size) (gfs:size-height im-size)))) 46 | (dotimes (i pixel-count) 47 | (cffi:with-foreign-slots ((blue green red reserved) 48 | (cffi:mem-aptr pix-tmp '(:struct pixel-packet) i) (:struct pixel-packet)) 49 | (cffi:with-foreign-slots ((gfs::rgbred gfs::rgbgreen gfs::rgbblue gfs::rgbreserved) 50 | (cffi:mem-aref pixels-pointer '(:struct gfs::rgbquad) i) (:struct gfs::rgbquad)) 51 | (setf gfs::rgbreserved 0 52 | gfs::rgbred (scale-quantum-to-byte red) 53 | gfs::rgbgreen (scale-quantum-to-byte green) 54 | gfs::rgbblue (scale-quantum-to-byte blue)))))) 55 | pixels-pointer) 56 | 57 | (defmethod gfg:size ((self magick-data-plugin)) 58 | (let ((handle (gfs:handle self)) 59 | (size (gfs:make-size))) 60 | (if (or (null handle) (cffi:null-pointer-p handle)) 61 | (error 'gfs:disposed-error)) 62 | (cffi:with-foreign-slots ((rows columns) handle magick-image) 63 | (setf (gfs:size-height size) rows) 64 | (setf (gfs:size-width size) columns)) 65 | size)) 66 | 67 | (defmethod (setf gfg:size) (size (self magick-data-plugin)) 68 | (let ((handle (gfs:handle self)) 69 | (new-handle (cffi:null-pointer)) 70 | (ex (acquire-exception-info))) 71 | (if (or (null handle) (cffi:null-pointer-p handle)) 72 | (error 'gfs:disposed-error)) 73 | (unwind-protect 74 | (progn 75 | (setf new-handle (resize-image handle 76 | (gfs:size-width size) 77 | (gfs:size-height size) 78 | (cffi:foreign-enum-value 'filter-types :lanczos) 79 | 1.0 ex)) 80 | (if (gfs:null-handle-p new-handle) 81 | (error 'gfs:toolkit-error :detail (format nil 82 | "could not resize: ~a" 83 | (cffi:foreign-slot-value ex 84 | 'exception-info 85 | 'reason)))) 86 | (setf (slot-value self 'gfs:handle) new-handle) 87 | (destroy-image handle)) 88 | (destroy-exception-info ex))) 89 | size) 90 | 91 | (defmethod cffi:translate-to-foreign ((lisp-obj magick-data-plugin) 92 | (type gfs::bitmapinfo-pointer-type)) 93 | ;; FIXME: assume true-color for now 94 | ;; 95 | (gfg::make-initial-bitmapinfo lisp-obj)) 96 | -------------------------------------------------------------------------------- /src/uitoolkit/widgets/item-manager.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.widgets) 2 | 3 | ;;; 4 | ;;; helper functions 5 | ;;; 6 | 7 | (defun make-items-array (&optional (count 7)) 8 | (make-array count :fill-pointer 0 :adjustable t)) 9 | 10 | (defun call-text-provider (manager thing) 11 | (let ((func (text-provider-of manager)) 12 | (*print-readably* nil)) 13 | (cond 14 | ((stringp thing) 15 | thing) 16 | ((null func) 17 | (format nil "~a" thing)) 18 | (t 19 | (funcall func thing))))) 20 | 21 | (defun copy-item-sequence (handle new-items item-class) 22 | (let ((tc (thread-context)) 23 | (replacements (make-items-array))) 24 | (cond 25 | ((null new-items) 26 | replacements) 27 | ((vectorp new-items) 28 | (dotimes (i (length new-items)) 29 | (let ((item (elt new-items i))) 30 | (if (typep item item-class) 31 | (progn 32 | (setf (slot-value item 'gfs:handle) handle) 33 | (vector-push-extend item replacements)) 34 | (let ((tmp (make-instance item-class :handle handle :data item))) 35 | (put-item tc tmp) 36 | (vector-push-extend tmp replacements))))) 37 | replacements) 38 | ((listp new-items) 39 | (loop for item in new-items 40 | do (if (typep item item-class) 41 | (progn 42 | (setf (slot-value item 'gfs:handle) handle) 43 | (vector-push-extend item replacements)) 44 | (let ((tmp (make-instance item-class :handle handle :data item))) 45 | (put-item tc tmp) 46 | (vector-push-extend tmp replacements)))) 47 | replacements) 48 | (t 49 | (error 'gfs:toolkit-error :detail (format nil "invalid data structure type: ~a" new-items)))))) 50 | 51 | ;;; 52 | ;;; methods 53 | ;;; 54 | 55 | (defmethod append-item :before ((self item-manager) thing (disp event-dispatcher) &optional checked disabled classname) 56 | (declare (ignore thing disp checked disabled classname)) 57 | (if (gfs:disposed-p self) 58 | (error 'gfs:disposed-error))) 59 | 60 | (defmethod delete-all ((self item-manager)) 61 | (let ((items (slot-value self 'items))) 62 | (dotimes (i (length items)) 63 | (gfs:dispose (aref items i)))) 64 | (setf (slot-value self 'items) (make-items-array))) 65 | 66 | (defmethod delete-item :before ((self item-manager) index) 67 | (declare (ignore index)) 68 | (if (gfs:disposed-p self) 69 | (error 'gfs:disposed-error))) 70 | 71 | (defmethod delete-item ((self item-manager) index) 72 | (if (or (< index 0) (>= index (length (slot-value self 'items)))) 73 | (error 'gfs:toolkit-error :detail "invalid item index")) 74 | (multiple-value-bind (new-items victim) 75 | (gfs::remove-element (slot-value self 'items) index #'make-items-array) 76 | (setf (slot-value self 'items) new-items) 77 | (gfs:dispose victim))) 78 | 79 | (defmethod delete-selection :before ((self item-manager)) 80 | (if (gfs:disposed-p self) 81 | (error 'gfs:disposed-error))) 82 | 83 | (defmethod delete-span :before ((self item-manager) (sp gfs:span)) 84 | (declare (ignore sp)) 85 | (if (gfs:disposed-p self) 86 | (error 'gfs:disposed-error))) 87 | 88 | (defmethod gfs:dispose ((self item-manager)) 89 | (let ((items (slot-value self 'items)) 90 | (tc (thread-context))) 91 | (dotimes (i (length items)) 92 | (delete-tc-item tc (elt items i))))) 93 | 94 | (defmethod item-count :before ((self item-manager)) 95 | (if (gfs:disposed-p self) 96 | (error 'gfs:disposed-error))) 97 | 98 | (defmethod item-count ((self item-manager)) 99 | (length (slot-value self 'items))) 100 | 101 | (defmethod item-index :before ((self item-manager) (it item)) 102 | (declare (ignore it)) 103 | (if (gfs:disposed-p self) 104 | (error 'gfs:disposed-error))) 105 | 106 | (defmethod item-index ((self item-manager) (it item)) 107 | (let ((pos (position it (slot-value self 'items) :test #'items-equal))) 108 | (if (null pos) 109 | (return-from item-index 0)) 110 | pos)) 111 | 112 | (defmethod items-of ((self item-manager)) 113 | (coerce (slot-value self 'items) 'list)) 114 | 115 | (defmethod selected-items :before ((self item-manager)) 116 | (if (gfs:disposed-p self) 117 | (error 'gfs:disposed-error))) 118 | 119 | (defmethod (setf selected-items) :before (items (self item-manager)) 120 | (declare (ignore items)) 121 | (if (gfs:disposed-p self) 122 | (error 'gfs:disposed-error))) 123 | 124 | (defmethod update-from-items :before ((self item-manager)) 125 | (if (gfs:disposed-p self) 126 | (error 'gfs:disposed-error))) 127 | -------------------------------------------------------------------------------- /src/demos/unblocked/unblocked-window.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.tests) 2 | 3 | (defconstant +spacing+ 4) 4 | (defconstant +margin+ 4) 5 | 6 | (defvar *scoreboard-panel* nil) 7 | (defvar *tiles-panel* nil) 8 | (defvar *unblocked-win* nil) 9 | 10 | (defun get-unblocked-win () 11 | *unblocked-win*) 12 | 13 | (defun get-tiles-panel () 14 | *tiles-panel*) 15 | 16 | (defun get-scoreboard-panel () 17 | *scoreboard-panel*) 18 | 19 | (defun new-unblocked (disp item) 20 | (declare (ignore disp item)) 21 | (ctrl-start-game)) 22 | 23 | (defun restart-unblocked (disp item) 24 | (declare (ignore disp item)) 25 | (ctrl-restart-game)) 26 | 27 | (defun update-panel (panel) 28 | (update-buffer (gfw:dispatcher panel)) 29 | (gfw:redraw panel)) 30 | 31 | (defun update-status-bar (msg) 32 | (if *unblocked-win* 33 | (setf (gfw:text (gfw:status-bar-of *unblocked-win*)) msg))) 34 | 35 | (defun reveal-unblocked (disp item) 36 | (declare (ignore disp item)) 37 | (ctrl-reveal-move)) 38 | 39 | (defun quit-unblocked (disp item) 40 | (declare (ignore disp item)) 41 | (setf *scoreboard-panel* nil) 42 | (setf *tiles-panel* nil) 43 | (gfs:dispose *unblocked-win*) 44 | (setf *unblocked-win* nil) 45 | (gfw:shutdown 0)) 46 | 47 | (defclass unblocked-win-events (gfw:event-dispatcher) ()) 48 | 49 | (defmethod gfw:event-close ((disp unblocked-win-events) window) 50 | (declare (ignore window)) 51 | (quit-unblocked disp nil)) 52 | 53 | (defmethod gfw:event-timer ((disp unblocked-win-events) timer) 54 | (declare (ignore timer)) 55 | (update-panel *tiles-panel*)) 56 | 57 | (defun about-unblocked (disp item) 58 | (declare (ignore disp item)) 59 | (let* ((*default-pathname-defaults* (parse-namestring *unblocked-dir*)) 60 | (image-path (merge-pathnames "about.bmp"))) 61 | (about-demo *unblocked-win* image-path "About UnBlocked" "UnBlocked version 0.9"))) 62 | 63 | (defun unblocked-startup () 64 | (let ((menubar (gfw:defmenu ((:item "&File" 65 | :submenu ((:item "&New" :callback #'new-unblocked) 66 | (:item "&Restart" :callback #'restart-unblocked) 67 | (:item "Reveal &Move" :callback #'reveal-unblocked) 68 | (:item "" :separator) 69 | (:item "E&xit" :callback #'quit-unblocked))) 70 | (:item "&Help" 71 | :submenu ((:item "&About UnBlocked" :callback #'about-unblocked)))))) 72 | (scoreboard-buffer-size (compute-scoreboard-size)) 73 | (tile-buffer-size (gfs:make-size :width (+ (* +horz-tile-count+ +tile-bmp-width+) 74 | 2) 75 | :height (+ (* +vert-tile-count+ +tile-bmp-height+) 76 | 2)))) 77 | (setf *unblocked-win* (make-instance 'gfw:top-level :dispatcher (make-instance 'unblocked-win-events) 78 | :layout (make-instance 'gfw:flow-layout 79 | :style :vertical 80 | :spacing +spacing+ 81 | :margins +margin+) 82 | :style '(:fixed-size :workspace :status-bar))) 83 | (setf (gfw:menu-bar *unblocked-win*) menubar) 84 | (setf *scoreboard-panel* (make-instance 'scoreboard-panel 85 | :parent *unblocked-win* 86 | :style '(:border) 87 | :dispatcher (make-instance 'scoreboard-panel-events 88 | :buffer-size scoreboard-buffer-size))) 89 | (setf *tiles-panel* (make-instance 'tiles-panel 90 | :parent *unblocked-win* 91 | :style '(:border) 92 | :dispatcher (make-instance 'tiles-panel-events 93 | :buffer-size tile-buffer-size))) 94 | (setf (gfw:text *unblocked-win*) "UnBlocked") 95 | 96 | (gfw:pack *unblocked-win*) 97 | 98 | (new-unblocked nil nil) 99 | (let ((*default-pathname-defaults* (parse-namestring *unblocked-dir*))) 100 | (setf (gfw:image *unblocked-win*) 101 | (make-instance 'gfg:icon-bundle :file (merge-pathnames "unblocked.ico")))) 102 | (gfw:show *unblocked-win* t))) 103 | 104 | (defun unblocked () 105 | (gfw:startup "UnBlocked" #'unblocked-startup)) 106 | -------------------------------------------------------------------------------- /src/uitoolkit/widgets/status-bar.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.widgets) 2 | 3 | ;;; 4 | ;;; helper functions 5 | ;;; 6 | 7 | (declaim (inline stb-is-simple)) 8 | (defun stb-is-simple (status-bar) 9 | (/= (gfs::send-message (gfs:handle status-bar) gfs::+sb-issimple+ 0 0) 0)) 10 | 11 | (defun stb-get-border-widths (status-bar) 12 | "Returns a list of integer widths (0: horz border, 1: vert border, 2: internal)" 13 | (cffi:with-foreign-pointer (array (* (cffi:foreign-type-size :int) 3)) 14 | (when (zerop (gfs::send-message (gfs:handle status-bar) 15 | gfs::+sb-getborders+ 16 | 0 17 | (cffi:pointer-address array))) 18 | (warn 'gfs:win32-warning :detail "SB_GETBORDERS message failed") 19 | (return-from stb-get-border-widths (list 0 0 0))) 20 | (loop for index from 0 to 2 21 | collect (cffi:mem-aref array :int index)))) 22 | 23 | (defun stb-set-min-height (status-bar height) 24 | (let ((widths (stb-get-border-widths status-bar)) 25 | (hstatus (gfs:handle status-bar))) 26 | (when (zerop (gfs::send-message hstatus 27 | gfs::+sb-setminheight+ 28 | (+ height (* (second widths) 2)) 29 | 0)) 30 | (warn 'gfs:win32-warning :detail "SB_SETMINHEIGHT message failed") 31 | (return-from stb-set-min-height nil)) 32 | (gfs::send-message hstatus gfs::+wm-size+ 0 0)) 33 | height) 34 | 35 | (defun stb-set-text (status-bar str &optional item-index) 36 | (let ((part-id (if (stb-is-simple status-bar) gfs::+sb-simpleid+ item-index))) 37 | (cffi:with-foreign-string (str-ptr str) 38 | (if (zerop (gfs::send-message (gfs:handle status-bar) 39 | gfs::+sb-settext+ 40 | part-id 41 | (cffi:pointer-address str-ptr))) 42 | (warn 'gfs:win32-warning :detail "SB_SETTEXT message failed")))) 43 | str) 44 | 45 | (defun stb-get-text-properties (status-bar item-index) 46 | "Returns the text length and operation type of the status bar part at item-index." 47 | (let ((hresult (gfs::send-message (gfs:handle status-bar) 48 | gfs::+sb-gettextlength+ 49 | item-index 50 | 0))) 51 | (values (gfs::lparam-low-word hresult) (gfs::lparam-high-word hresult)))) 52 | 53 | (defun stb-get-text (status-bar item-index) 54 | (multiple-value-bind (length op-type) 55 | (stb-get-text-properties status-bar item-index) 56 | (declare (ignore op-type)) 57 | (if (zerop length) 58 | "" 59 | (cffi:with-foreign-pointer-as-string (str-ptr (1+ length)) 60 | (gfs::send-message (gfs:handle status-bar) 61 | gfs::+sb-gettext+ 62 | item-index 63 | (cffi:pointer-address str-ptr)))))) 64 | 65 | ;;; 66 | ;;; methods 67 | ;;; 68 | 69 | (defmethod border-width ((self status-bar)) 70 | (let ((widths (stb-get-border-widths self))) 71 | (max (first widths) (second widths)))) 72 | 73 | (defmethod compute-style-flags ((self status-bar) &rest extra-data) 74 | (let ((extra-bits (if (first extra-data) 0 gfs::+sbars-sizegrip+))) 75 | (values (logior gfs::+ws-child+ gfs::+ws-visible+ extra-bits) 0))) 76 | 77 | (defmethod initialize-instance :after ((self status-bar) &key parent &allow-other-keys) 78 | (let ((hctl (create-control self 79 | parent 80 | "" 81 | gfs::+icc-win95-classes+ 82 | nil 83 | (find :fixed-size (style-of parent))))) 84 | (gfs::send-message hctl gfs::+sb-simple+ 1 0)) 85 | (let ((widths (stb-get-border-widths self))) 86 | (setf (layout-of self) (make-instance 'flow-layout :spacing (third widths))))) 87 | 88 | (defmethod preferred-size ((self status-bar) width-hint height-hint) 89 | (declare (ignore height-hint)) 90 | (if (gfs:disposed-p self) 91 | (error 'gfs:disposed-error)) 92 | (let ((tmp-size (if (data-of (layout-of self)) 93 | (compute-size (layout-of self) self width-hint -1) 94 | (widget-text-size self 95 | (lambda (widget) 96 | (declare (ignore widget)) 97 | "X") 98 | gfs::+dt-singleline+))) 99 | (widths (stb-get-border-widths self))) 100 | (gfs:make-size :width 0 101 | :height (+ (gfs:size-height tmp-size) (* (second widths) 2) 1)))) 102 | 103 | (defmethod text ((sbar status-bar)) 104 | (stb-get-text sbar 0)) 105 | 106 | (defmethod (setf text) (str (sbar status-bar)) 107 | (stb-set-text sbar str)) 108 | -------------------------------------------------------------------------------- /src/uitoolkit/graphics/font-data.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.graphics) 2 | 3 | (defun pntsize->lfheight (hdc pntsize) 4 | (let ((log-height (gfs::get-device-caps hdc gfs::+logpixelsy+))) 5 | (- (floor (+ (/ (* pntsize log-height) 72) 0.5))))) 6 | 7 | (defun lfheight->pntsize (hdc lfheight) 8 | (let ((log-height (gfs::get-device-caps hdc gfs::+logpixelsy+))) 9 | (floor (* (+ (- lfheight) 0.5) 72) log-height))) 10 | 11 | (defun style->logfont (style lf-ptr) 12 | (cffi:with-foreign-slots ((gfs::lfweight gfs::lfitalic gfs::lfunderline 13 | gfs::lfstrikeout gfs::lfoutprec gfs::lfpitchandfamily) 14 | lf-ptr (:struct gfs::logfont)) 15 | (setf gfs::lfweight (if (find :bold style) gfs::+fw-bold+ gfs::+fw-normal+)) 16 | (setf gfs::lfitalic (if (find :italic style) 1 0)) 17 | (setf gfs::lfunderline (if (find :underline style) 1 0)) 18 | (setf gfs::lfstrikeout (if (find :strikeout style) 1 0)) 19 | (setf gfs::lfoutprec (cond 20 | ((find :truetype-only style) gfs::+out-tt-only-precis+) 21 | ((find :outline style) gfs::+out-outline-precis+) 22 | (t gfs::+out-default-precis+))) 23 | (setf gfs::lfpitchandfamily (cond 24 | ((find :fixed style) gfs::+fixed-pitch+) 25 | ((find :variable style) gfs::+variable-pitch+) 26 | (t gfs::+default-pitch+))))) 27 | 28 | (defun logfont->style (lf-ptr) 29 | (let ((style nil)) 30 | (cffi:with-foreign-slots ((gfs::lfweight gfs::lfitalic gfs::lfunderline 31 | gfs::lfstrikeout gfs::lfoutprec gfs::lfpitchandfamily) 32 | lf-ptr (:struct gfs::logfont)) 33 | (if (= gfs::lfweight gfs::+fw-bold+) 34 | (push :bold style)) 35 | (unless (zerop gfs::lfitalic) 36 | (push :italic style)) 37 | (unless (zerop gfs::lfunderline) 38 | (push :underline style)) 39 | (unless (zerop gfs::lfstrikeout) 40 | (push :strikeout style)) 41 | (case gfs::lfoutprec 42 | (#.gfs::+out-tt-only-precis+ (push :truetype-only style)) 43 | (#.gfs::+out-outline-precis+ (push :outline style))) 44 | (case gfs::lfpitchandfamily 45 | (#.gfs::+fixed-pitch+ (push :fixed style)) 46 | (#.gfs::+variable-pitch+ (push :variable style)))) 47 | style)) 48 | 49 | (defun data->logfont (hdc data) 50 | (let ((lf-ptr (cffi:foreign-alloc '(:struct gfs::logfont))) 51 | (style (font-data-style data))) 52 | (gfs:zero-mem lf-ptr (:struct gfs::logfont)) 53 | (cffi:with-foreign-slots ((gfs::lfheight gfs::lfcharset gfs::lffacename) lf-ptr (:struct gfs::logfont)) 54 | (setf gfs::lfheight (pntsize->lfheight hdc (font-data-point-size data))) 55 | (setf gfs::lfcharset (font-data-char-set data)) 56 | (style->logfont style lf-ptr) 57 | (cffi:with-foreign-string (str (font-data-face-name data)) 58 | (let ((lffacename-ptr (cffi:foreign-slot-pointer lf-ptr '(:struct gfs::logfont) 'gfs::lffacename))) 59 | (gfs::strncpy lffacename-ptr str (1- gfs::+lf-facesize+)) 60 | (setf (cffi:mem-aref lffacename-ptr :char (1- gfs::+lf-facesize+)) 0)))) 61 | lf-ptr)) 62 | 63 | (defun logfont->data (hdc lf-ptr) 64 | (let ((char-set 0) 65 | (face-name "") 66 | (point-size 0) 67 | (style nil)) 68 | (cffi:with-foreign-slots ((gfs::lfheight gfs::lfcharset gfs::lffacename) lf-ptr (:struct gfs::logfont)) 69 | (setf point-size (lfheight->pntsize hdc gfs::lfheight)) 70 | (setf char-set gfs::lfcharset) 71 | (setf style (logfont->style lf-ptr)) 72 | (let ((lffacename-ptr (cffi:foreign-slot-pointer lf-ptr '(:struct gfs::logfont) 'gfs::lffacename))) 73 | (setf face-name (cffi:foreign-string-to-lisp lffacename-ptr)))) 74 | (gfg:make-font-data :char-set char-set 75 | :face-name face-name 76 | :point-size point-size 77 | :style style))) 78 | 79 | (defun data->font (hdc data) 80 | (let ((hfont (cffi:null-pointer))) 81 | (setf hfont (gfs::create-font-indirect (data->logfont hdc data))) 82 | (if (gfs:null-handle-p hfont) 83 | (error 'gfs:win32-error :detail "create-font-indirect failed")) 84 | hfont)) 85 | 86 | (defun font->data (hdc hfont) 87 | (cffi:with-foreign-object (lf-ptr '(:struct gfs::logfont)) 88 | (gfs:zero-mem lf-ptr (:struct gfs::logfont)) 89 | (if (zerop (gfs::get-object hfont (cffi:foreign-type-size '(:struct gfs::logfont)) lf-ptr)) 90 | (error 'gfs:win32-error :detail "get-object failed")) 91 | (logfont->data hdc lf-ptr))) 92 | 93 | (defmethod print-object ((self font-data) stream) 94 | (print-unreadable-object (self stream :type t) 95 | (format stream "face name: ~a " (font-data-face-name self)) 96 | (format stream "point size: ~d " (font-data-point-size self)) 97 | (format stream "style: ~a " (font-data-style self)) 98 | (format stream "char-set: ~d" (font-data-char-set self)))) 99 | -------------------------------------------------------------------------------- /src/uitoolkit/widgets/font-dialog.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.widgets) 2 | 3 | (defconstant +font-dialog-flags+ (logior gfs::+cf-effects+ gfs::+cf-inittologfontstruct+)) 4 | 5 | ;;; 6 | ;;; helper functions 7 | ;;; 8 | 9 | (defun obtain-chosen-font (dlg gc) 10 | (if (or (gfs:disposed-p dlg) (gfs:disposed-p gc)) 11 | (error 'gfs:disposed-error)) 12 | (cffi:with-foreign-slots ((gfs::logfont gfs::color) (gfs:handle dlg) (:struct gfs::choosefont)) 13 | (values (make-instance 'gfg:font :handle (gfs::create-font-indirect gfs::logfont)) 14 | (gfg::rgb->color gfs::color)))) 15 | 16 | (defun lookup-default-font () 17 | (let ((lf-ptr (cffi:foreign-alloc '(:struct gfs::logfont)))) 18 | (gfs:zero-mem lf-ptr (:struct gfs::logfont)) 19 | (gfs::get-object (gfs::get-stock-object gfs::+system-font+) 20 | (cffi:foreign-type-size '(:struct gfs::logfont)) 21 | lf-ptr) 22 | lf-ptr)) 23 | 24 | (defmacro with-font-dialog ((owner style font color &key gc initial-color initial-font) &body body) 25 | (let ((dlg (gensym))) 26 | `(let ((,font nil) 27 | (,color nil) 28 | (,dlg (make-instance 'font-dialog 29 | :gc ,gc 30 | :initial-color ,initial-color 31 | :initial-font ,initial-font 32 | :owner ,owner 33 | :style ,style))) 34 | (unwind-protect 35 | (unless (zerop (show ,dlg t)) 36 | (multiple-value-bind (f c) (obtain-chosen-font ,dlg ,gc) 37 | (setf ,font f) 38 | (setf ,color c)) 39 | ,@body) 40 | (gfs:dispose ,dlg))))) 41 | 42 | ;;; 43 | ;;; methods 44 | ;;; 45 | 46 | (defmethod compute-style-flags ((self font-dialog) &rest extra-data) 47 | (declare (ignore extra-data)) 48 | (let ((std-flags (logior gfs::+cf-both+ +font-dialog-flags+))) 49 | (loop for sym in (style-of self) 50 | do (ecase sym 51 | ;; primary styles 52 | ;; 53 | (:all-fonts 54 | (setf std-flags (logior gfs::+cf-both+ +font-dialog-flags+))) 55 | (:fixed-pitch-fonts 56 | (setf std-flags (logior gfs::+cf-fixedpitchonly+ +font-dialog-flags+))) 57 | (:printer-fonts 58 | (setf std-flags (logior gfs::+cf-printerfonts+ +font-dialog-flags+))) 59 | (:screen-fonts 60 | (setf std-flags (logior gfs::+cf-screenfonts+ +font-dialog-flags+))) 61 | (:truetype-fonts 62 | (setf std-flags (logior gfs::+cf-ttonly+ +font-dialog-flags+))) 63 | (:wsyiwyg-fonts 64 | (setf std-flags (logior gfs::+cf-both+ 65 | gfs::+cf-scalableonly+ 66 | gfs::+cf-wysiwyg+ 67 | +font-dialog-flags+))) 68 | 69 | ;; styles that can be combined 70 | ;; 71 | (:no-effects 72 | (setf std-flags (logand std-flags (lognot gfs::+cf-effects+)))))) 73 | (values std-flags 0))) 74 | 75 | (defmethod gfs:dispose ((self font-dialog)) 76 | (let ((cf-ptr (gfs:handle self))) 77 | (unless (cffi:null-pointer-p cf-ptr) 78 | (cffi:with-foreign-slots ((gfs::logfont) cf-ptr (:struct gfs::choosefont)) 79 | (unless (cffi:null-pointer-p gfs::logfont) 80 | (cffi:foreign-free gfs::logfont))) 81 | (cffi:foreign-free cf-ptr))) 82 | (setf (slot-value self 'gfs:handle) (cffi:null-pointer))) 83 | 84 | (defmethod initialize-instance :after ((self font-dialog) &key gc initial-color initial-font owner &allow-other-keys) 85 | (if (null gc) 86 | (error 'gfs:toolkit-error :detail ":gc initarg is required")) 87 | (if (null owner) 88 | (error 'gfs:toolkit-error :detail ":owner initarg is required")) 89 | (if (gfs:disposed-p owner) 90 | (error 'gfs:disposed-error)) 91 | (let ((cf-ptr (cffi:foreign-alloc '(:struct gfs::choosefont))) 92 | (lf-ptr (if initial-font 93 | (gfg::data->logfont (gfs:handle gc) (gfg:data-object initial-font gc)) 94 | (lookup-default-font)))) 95 | (multiple-value-bind (std-style ex-style) (compute-style-flags self) 96 | (declare (ignore ex-style)) 97 | (cffi:with-foreign-slots ((gfs::structsize gfs::howner gfs::hdc gfs::logfont 98 | gfs::flags gfs::color) 99 | cf-ptr (:struct gfs::choosefont)) 100 | (setf gfs::structsize (cffi:foreign-type-size '(:struct gfs::choosefont)) 101 | gfs::howner (gfs:handle owner) 102 | gfs::hdc (gfs:handle gc) 103 | gfs::logfont lf-ptr 104 | gfs::flags std-style 105 | gfs::color (if initial-color (gfg:color->rgb initial-color) 0)))) 106 | (setf (slot-value self 'gfs:handle) cf-ptr))) 107 | 108 | (defmethod show ((self font-dialog) flag) 109 | (declare (ignore flag)) 110 | (show-common-dialog self #'gfs::choose-font)) 111 | -------------------------------------------------------------------------------- /src/tests/uitoolkit/icon-bundle-unit-tests.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.tests) 2 | 3 | (define-test bmp-file-icon-bundle-test 4 | (let ((bundle (make-instance 'gfg:icon-bundle :file (merge-pathnames "uitoolkit/happy.bmp" *gf-tests-dir*))) 5 | (size (gfs:make-size :width 32 :height 32))) 6 | (unwind-protect 7 | (progn 8 | (assert-equal 1 (gfg:icon-bundle-length bundle)) 9 | (validate-image (gfg:icon-image-ref bundle 0) size 8) 10 | (validate-image (gfg:icon-image-ref bundle :large) size 8) 11 | (validate-image (gfg:icon-image-ref bundle :small) size 8)) 12 | (gfs:dispose bundle)) 13 | (assert-true (gfs:disposed-p bundle)))) 14 | 15 | (define-test images-icon-bundle-test 16 | (let ((bundle (make-instance 'gfg:icon-bundle 17 | :images (list (make-instance 'gfg:image :file (merge-pathnames "uitoolkit/happy.bmp" *gf-tests-dir*)) 18 | (make-instance 'gfg:image :file (merge-pathnames "uitoolkit/blackwhite20x16.bmp" *gf-tests-dir*)) 19 | (make-instance 'gfg:image :file (merge-pathnames "uitoolkit/truecolor16x16.bmp" *gf-tests-dir*))))) 20 | (happy-size (gfs:make-size :width 32 :height 32)) 21 | (bw-size (gfs:make-size :width 20 :height 16)) 22 | (tc-size (gfs:make-size :width 16 :height 16))) 23 | (unwind-protect 24 | (progn 25 | (assert-equal 3 (gfg:icon-bundle-length bundle)) 26 | (validate-image (gfg:icon-image-ref bundle 0) happy-size 8) 27 | (validate-image (gfg:icon-image-ref bundle 1) bw-size 8) 28 | (validate-image (gfg:icon-image-ref bundle 2) tc-size 16000000) 29 | (validate-image (gfg:icon-image-ref bundle :small) tc-size 8) 30 | (validate-image (gfg:icon-image-ref bundle :large) happy-size 8)) 31 | (gfs:dispose bundle)) 32 | (assert-true (gfs:disposed-p bundle)))) 33 | 34 | (define-test push-images-icon-bundle-test 35 | (let ((bundle (make-instance 'gfg:icon-bundle)) 36 | (happy-image (make-instance 'gfg:image :file (merge-pathnames "uitoolkit/happy.bmp" *gf-tests-dir*))) 37 | (bw-image (make-instance 'gfg:image :file (merge-pathnames "uitoolkit/blackwhite20x16.bmp" *gf-tests-dir*))) 38 | (tc-image (make-instance 'gfg:image :file (merge-pathnames "uitoolkit/truecolor16x16.bmp" *gf-tests-dir*))) 39 | (happy-size (gfs:make-size :width 32 :height 32)) 40 | (bw-size (gfs:make-size :width 20 :height 16)) 41 | (tc-size (gfs:make-size :width 16 :height 16)) 42 | (bw-point (gfs:make-point :x 0 :y 15))) 43 | (unwind-protect 44 | (progn 45 | (gfg:push-icon-image bw-image bundle bw-point) 46 | (gfg:push-icon-image tc-image bundle) 47 | (gfg:push-icon-image happy-image bundle) 48 | (assert-equal 3 (gfg:icon-bundle-length bundle)) 49 | (validate-image (gfg:icon-image-ref bundle 0) happy-size 8) 50 | (validate-image (gfg:icon-image-ref bundle 1) tc-size 16000000) 51 | (validate-image (gfg:icon-image-ref bundle 2) bw-size 8) 52 | (validate-image (gfg:icon-image-ref bundle :small) tc-size 8) 53 | (validate-image (gfg:icon-image-ref bundle :large) happy-size 8)) 54 | (gfs:dispose bundle)) 55 | (assert-true (gfs:disposed-p bundle)))) 56 | 57 | (define-test system-icon-bundle-test 58 | (let ((size (gfs:make-size :width (gfs::get-system-metrics gfs::+sm-cxicon+) 59 | :height (gfs::get-system-metrics gfs::+sm-cyicon+))) 60 | (bundle (make-instance 'gfg:icon-bundle :system gfg:+warning-icon+))) 61 | (unwind-protect 62 | (progn 63 | (assert-equal 1 (gfg:icon-bundle-length bundle)) 64 | (validate-image (gfg:icon-image-ref bundle 0) size 8) 65 | (validate-image (gfg:icon-image-ref bundle :small) size 8) 66 | (validate-image (gfg:icon-image-ref bundle :large) size 8)) 67 | (gfs:dispose bundle)) 68 | (assert-true (gfs:disposed-p bundle)))) 69 | 70 | (define-test setf-images-icon-bundle-test 71 | (let ((bundle (make-instance 'gfg:icon-bundle 72 | :images (list (make-instance 'gfg:image :file (merge-pathnames "uitoolkit/happy.bmp" *gf-tests-dir*)) 73 | (make-instance 'gfg:image :file (merge-pathnames "uitoolkit/truecolor16x16.bmp" *gf-tests-dir*))))) 74 | (happy-image (make-instance 'gfg:image :file (merge-pathnames "uitoolkit/happy.bmp" *gf-tests-dir*))) 75 | (bw-image (make-instance 'gfg:image :file (merge-pathnames "uitoolkit/blackwhite20x16.bmp" *gf-tests-dir*))) 76 | (happy-size (gfs:make-size :width 32 :height 32)) 77 | (bw-size (gfs:make-size :width 20 :height 16))) 78 | (unwind-protect 79 | (progn 80 | (assert-equal 2 (gfg:icon-bundle-length bundle)) 81 | (setf (gfg:icon-image-ref bundle 0) bw-image) 82 | (setf (gfg:icon-image-ref bundle 1) happy-image) 83 | (assert-equal 2 (gfg:icon-bundle-length bundle)) 84 | (validate-image (gfg:icon-image-ref bundle 0) bw-size 16000000) 85 | (validate-image (gfg:icon-image-ref bundle 1) happy-size 8)) 86 | (gfs:dispose bundle)) 87 | (assert-true (gfs:disposed-p bundle)))) 88 | -------------------------------------------------------------------------------- /src/uitoolkit/widgets/display.lisp: -------------------------------------------------------------------------------- 1 | (in-package :graphic-forms.uitoolkit.widgets) 2 | 3 | ;;; 4 | ;;; helper functions 5 | ;;; 6 | 7 | (cffi:defcallback (display-visitor :convention :stdcall) gfs::BOOL 8 | ((hmonitor :pointer) (hdc :pointer) (monitorrect :pointer) (data gfs::LPARAM)) 9 | (declare (ignore hdc monitorrect)) 10 | (call-display-visitor-func (thread-context) hmonitor data) 11 | 1) 12 | 13 | (defun query-display-info (hmonitor) 14 | (let ((info nil)) 15 | (cffi:with-foreign-object (mi-ptr '(:struct gfs::monitorinfoex)) 16 | (cffi:with-foreign-slots ((gfs::cbsize gfs::flags) mi-ptr (:struct gfs::monitorinfoex)) 17 | (setf gfs::cbsize (cffi:foreign-type-size '(:struct gfs::monitorinfoex))) 18 | (if (zerop (gfs::get-monitor-info hmonitor mi-ptr)) 19 | (error 'gfs:win32-warning :detail "get-monitor-info failed")) 20 | (push (= (logand gfs::flags gfs::+monitorinfoof-primary+) gfs::+monitorinfoof-primary+) info) 21 | (let ((str-ptr (cffi:foreign-slot-pointer mi-ptr '(:struct gfs::monitorinfoex) 'gfs::device))) 22 | (push (cffi:foreign-string-to-lisp str-ptr :max-chars (1- gfs::+cchdevicename+)) info)) 23 | (let ((rect-ptr (cffi:foreign-slot-pointer mi-ptr '(:struct gfs::monitorinfoex) 'gfs::monitor))) 24 | (cffi:with-foreign-slots ((gfs::left gfs::top gfs::right gfs::bottom) 25 | rect-ptr (:struct gfs::rect)) 26 | (push (gfs:make-size :width (- gfs::right gfs::left) :height (- gfs::bottom gfs::top)) 27 | info))) 28 | (let ((rect-ptr (cffi:foreign-slot-pointer mi-ptr '(:struct gfs::monitorinfoex) 'gfs::work))) 29 | (cffi:with-foreign-slots ((gfs::left gfs::top gfs::right gfs::bottom) 30 | rect-ptr (:struct gfs::rect)) 31 | (push (gfs:make-size :width (- gfs::right gfs::left) :height (- gfs::bottom gfs::top)) 32 | info))))) 33 | (reverse info))) 34 | 35 | (defun mapdisplays (func) 36 | ;; 37 | ;; func should expect two parameters: 38 | ;; display handle 39 | ;; flag data 40 | ;; 41 | (let ((tc (thread-context))) 42 | (setf (display-visitor-func tc) func) 43 | (unwind-protect 44 | (gfs::enum-display-monitors (cffi:null-pointer) 45 | (cffi:null-pointer) 46 | (cffi:callback display-visitor) 0) 47 | (setf (display-visitor-func tc) nil)) 48 | (let ((tmp (reverse (display-visitor-results tc)))) 49 | (setf (display-visitor-results tc) nil) 50 | tmp))) 51 | 52 | (defun obtain-displays () 53 | (mapdisplays (lambda (hmonitor data) 54 | (declare (ignore data)) 55 | (push (make-instance 'display :handle hmonitor) 56 | (display-visitor-results (thread-context)))))) 57 | 58 | (declaim (inline obtain-primary-display)) 59 | (defun obtain-primary-display () 60 | ;; In http://blogs.msdn.com/oldnewthing/archive/2007/08/09/4300545.aspx 61 | ;; Raymond Chen recommends the following technique for obtaining the 62 | ;; primary display. 63 | ;; 64 | (make-instance 'display 65 | :handle (gfs::monitor-from-point 0 0 gfs::+monitor-defaulttoprimary+))) 66 | 67 | (cffi:defcallback (top-level-window-visitor :convention :stdcall) gfs::BOOL 68 | ((hwnd :pointer) (lparam gfs::LPARAM)) 69 | (declare (ignore lparam)) 70 | (let* ((tc (thread-context)) 71 | (win (get-widget tc hwnd))) 72 | (unless (null win) 73 | (call-top-level-visitor-func tc win))) 74 | 1) 75 | 76 | (defun maptoplevels (func) 77 | ;; 78 | ;; func should expect one parameter: 79 | ;; top-level window 80 | ;; 81 | (let ((tc (thread-context))) 82 | (setf (top-level-visitor-func tc) func) 83 | (unwind-protect 84 | (gfs::enum-thread-windows (gfs::get-window-thread-process-id (utility-hwnd tc) (cffi:null-pointer)) 85 | (cffi:callback top-level-window-visitor) 86 | 0) 87 | (setf (top-level-visitor-func tc) nil)) 88 | (let ((tmp (reverse (top-level-visitor-results tc)))) 89 | (setf (top-level-visitor-results tc) nil) 90 | tmp))) 91 | 92 | ;;; 93 | ;;; methods 94 | ;;; 95 | 96 | (defmethod client-size ((self display)) 97 | (if (gfs:disposed-p self) 98 | (error 'gfs:disposed-error)) 99 | (destructuring-bind (primary name size client-size) (query-display-info (gfs:handle self)) 100 | (declare (ignore primary name size)) 101 | client-size)) 102 | 103 | (defmethod gfs:dispose ((self display)) 104 | (setf (slot-value self 'gfs:handle) nil)) 105 | 106 | (defun primary-p (self) 107 | (if (gfs:disposed-p self) 108 | (error 'gfs:disposed-error)) 109 | (destructuring-bind (primary name size client-size) (query-display-info (gfs:handle self)) 110 | (declare (ignore name size client-size)) 111 | primary)) 112 | 113 | (defmethod size ((self display)) 114 | (if (gfs:disposed-p self) 115 | (error 'gfs:disposed-error)) 116 | (destructuring-bind (primary name size client-size) (query-display-info (gfs:handle self)) 117 | (declare (ignore primary name client-size)) 118 | size)) 119 | 120 | (defmethod text ((self display)) 121 | (if (gfs:disposed-p self) 122 | (error 'gfs:disposed-error)) 123 | (destructuring-bind (primary name size client-size) (query-display-info (gfs:handle self)) 124 | (declare (ignore primary size client-size)) 125 | name)) 126 | --------------------------------------------------------------------------------