port of EQL/Qt4 to Qt5
39
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
*.a
|
||||
*.dll
|
||||
*.dylib
|
||||
*.exe
|
||||
*.fas*
|
||||
*.*history
|
||||
*.lib
|
||||
*.o
|
||||
*.obj
|
||||
*.so*
|
||||
*.DS_Store
|
||||
*.qm
|
||||
*.ts
|
||||
*~
|
||||
*.~
|
||||
#*.*#
|
||||
.*.lisp
|
||||
.*.ui
|
||||
.*.txt
|
||||
*.user
|
||||
t.lisp
|
||||
tr.h
|
||||
moc_*.cpp
|
||||
Makefile
|
||||
eql
|
||||
eql5
|
||||
eql.app
|
||||
gui/.*
|
||||
my_app/my_app
|
||||
my_app/my_app.app/*
|
||||
my_app/.*
|
||||
src/ECL*
|
||||
src/tmp
|
||||
eql_profile*
|
||||
eql_local_server
|
||||
cache
|
||||
tmp
|
||||
palindrome.htm
|
||||
positions.js
|
||||
20
LICENSE-1.MIT
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
Copyright (c) 2010-2014 Polos (Paul) Ruetz
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
25
LICENSE-2-MAKE-QIMAGE.txt
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
;; Copyright (c) 2012, Mark Cox
|
||||
;; All rights reserved.
|
||||
|
||||
;; Redistribution and use in source and binary forms, with or without
|
||||
;; modification, are permitted provided that the following conditions are
|
||||
;; met:
|
||||
|
||||
;; - Redistributions of source code must retain the above copyright
|
||||
;; notice, this list of conditions and the following disclaimer.
|
||||
|
||||
;; - Redistributions in binary form must reproduce the above copyright
|
||||
;; notice, this list of conditions and the following disclaimer in the
|
||||
;; documentation and/or other materials provided with the distribution.
|
||||
|
||||
;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
;; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
;; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
;; HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
;; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
;; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
;; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
;; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
27
Qt_EQL/README.txt
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
BUILD / RUN
|
||||
===========
|
||||
|
||||
Build the plugins in "cpp/", "cpp_calling_lisp/" before running the examples.
|
||||
|
||||
See "trafficlight/" for an example of integrating a Qt/C++ application.
|
||||
|
||||
|
||||
|
||||
NOTES
|
||||
=====
|
||||
|
||||
This offers the same possibilities as found in the "Qt_EQL/" example,
|
||||
but with a better, more dynamic workflow, and without the restriction of
|
||||
"CONFIG += no_keywords" in your "*.pro" file.
|
||||
|
||||
So, integrating any existing Qt/C++ project is straightforward, since you can
|
||||
call any property/method/slot/signal of any Qt class (see QFIND-CHILD,
|
||||
QFIND-CHILDREN, QFUN+).
|
||||
|
||||
Calling Lisp from C++ through "eql_fun()" is easy, and you can use any Qt
|
||||
class/type supported by EQL, see examples in "cpp_calling_lisp/lib.cpp".
|
||||
|
||||
To automatically generate generic function wrappers for your Qt functions,
|
||||
see function DEFINE-QT-WRAPPERS.
|
||||
|
||||
Linux only: see also function QAUTO-RELOAD-C++.
|
||||
21
Qt_EQL/auto-reload.lisp
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
;;;
|
||||
;;; Linux only!
|
||||
;;;
|
||||
;;; just edit/recompile "cpp/*"
|
||||
;;;
|
||||
|
||||
(in-package :eql-user)
|
||||
|
||||
#+linux
|
||||
(qauto-reload-c++ *lib* (in-home "Qt_EQL/eql_cpp"))
|
||||
|
||||
#+linux
|
||||
(setf *lib-reloaded* 'show-current-apropos)
|
||||
|
||||
(defun show-current-apropos (variable plugin)
|
||||
(qset (qapp) "quitOnLastWindowClosed" nil)
|
||||
(let ((obj (symbol-value variable)))
|
||||
(assert (qt-object-p obj))
|
||||
(qmsg (with-output-to-string (*standard-output*)
|
||||
(format t "<b>Plugin ~S currently offers:</b><pre>" plugin)
|
||||
(qapropos nil obj)))))
|
||||
12
Qt_EQL/cpp/eql_cpp.pro
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
QT += widgets
|
||||
TEMPLATE = lib
|
||||
CONFIG += plugin release
|
||||
DESTDIR = ../
|
||||
TARGET = eql_cpp
|
||||
OBJECTS_DIR = ./tmp/
|
||||
MOC_DIR = ./tmp/
|
||||
|
||||
include(../../src/windows.pri)
|
||||
|
||||
HEADERS += lib.h
|
||||
SOURCES += lib.cpp
|
||||
32
Qt_EQL/cpp/lib.cpp
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#include "lib.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QObject* ini()
|
||||
{
|
||||
// any QObject inherited class will do (e.g. main window of a C++ application)
|
||||
static QObject* cpp = 0;
|
||||
if(!cpp) {
|
||||
cpp = new CPP;
|
||||
cpp->setObjectName("Qt_EQL_dynamic");
|
||||
}
|
||||
return cpp;
|
||||
}
|
||||
|
||||
// insert here your function implementations
|
||||
|
||||
QVariantList CPP::hello(const QVariantList& list)
|
||||
{
|
||||
QString msg;
|
||||
QDebug debug(&msg);
|
||||
debug << list;
|
||||
QMessageBox::information(0, "QVariantList", msg);
|
||||
|
||||
QVariantList ret(list);
|
||||
if(!ret.isEmpty()) {
|
||||
ret[0] = "hello from Lisp";
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
26
Qt_EQL/cpp/lib.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef LIB_H
|
||||
#define LIB_H
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
#ifdef Q_WS_WIN
|
||||
#define LIB_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define LIB_EXPORT
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
extern "C" { LIB_EXPORT QObject* ini(); }
|
||||
|
||||
class CPP : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
// insert here your function declarations, prepended by Q_INVOKABLE
|
||||
Q_INVOKABLE QVariantList hello(const QVariantList&);
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif
|
||||
13
Qt_EQL/cpp_calling_lisp/eql_cpp.pro
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
QT += widgets
|
||||
TEMPLATE = lib
|
||||
CONFIG += plugin release
|
||||
LIBS += -L../.. -leql5
|
||||
DESTDIR = ../
|
||||
TARGET = eql_fun_cpp
|
||||
OBJECTS_DIR = ./tmp/
|
||||
MOC_DIR = ./tmp/
|
||||
|
||||
include(../../src/windows.pri)
|
||||
|
||||
HEADERS += lib.h
|
||||
SOURCES += lib.cpp
|
||||
62
Qt_EQL/cpp_calling_lisp/lib.cpp
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#include "lib.h"
|
||||
#include "../../src/eql_fun.h" // for eql_fun()
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QObject* ini()
|
||||
{
|
||||
// any QObject inherited class will do (e.g. main window of a C++ application)
|
||||
static QObject* cpp = 0;
|
||||
if(!cpp) {
|
||||
cpp = new CPP;
|
||||
cpp->setObjectName("Qt_EQL_dynamic");
|
||||
}
|
||||
return cpp;
|
||||
}
|
||||
|
||||
// insert here your function implementations
|
||||
|
||||
void CPP::runExamples()
|
||||
{
|
||||
ulong n = 123;
|
||||
|
||||
// (1) call user defined function
|
||||
{
|
||||
QVariant ret = eql_fun("eql-user:say-number", QVariant::String, // see: ecl_fun.cpp:toQVariant()
|
||||
Q_ARG(ulong, n)); // see: ecl_fun.cpp:to_lisp_arg()
|
||||
|
||||
QMessageBox::information(0, "Example 1",
|
||||
"<pre><b>eql_fun(\"eql-user:say-number\"...);</b><br><br>" + ret.toString());
|
||||
}
|
||||
|
||||
// (2) call FORMAT directly
|
||||
{
|
||||
QVariant ret = eql_fun("format", QVariant::String,
|
||||
Q_ARG(bool, false), // max. 10 Q_ARG()
|
||||
Q_ARG(QString, "~R"),
|
||||
Q_ARG(ulong, n));
|
||||
|
||||
QMessageBox::information(0, "Example 2",
|
||||
"<pre><b>eql_fun(\"format\"...);</b><br><br>" + ret.toString());
|
||||
}
|
||||
|
||||
// (3) returning a pointer
|
||||
{
|
||||
QVariant ret = eql_fun("qnew", QMetaType::VoidStar,
|
||||
Q_ARG(QString, "QLabel"));
|
||||
|
||||
QLabel* object = Q_PTR(QLabel*, ret); // type checked at run time; 0 if check fails
|
||||
if(object) {
|
||||
// ...
|
||||
}
|
||||
|
||||
QString msg;
|
||||
QDebug out(&msg);
|
||||
out << "<p>Q_PTR returned:<b>" << object << "</b></p><p>(type checked at run time)</p>";
|
||||
|
||||
QMessageBox::information(0, "Example 3",
|
||||
"<pre><b>eql_fun(\"qnew\"...);</b>" + msg);
|
||||
}
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
26
Qt_EQL/cpp_calling_lisp/lib.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef LIB_H
|
||||
#define LIB_H
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
#ifdef Q_WS_WIN
|
||||
#define LIB_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define LIB_EXPORT
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
extern "C" { LIB_EXPORT QObject* ini(); }
|
||||
|
||||
class CPP : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
// insert here your function declarations, prepended by Q_INVOKABLE
|
||||
Q_INVOKABLE void runExamples();
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif
|
||||
15
Qt_EQL/looping.lisp
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
;;; Lisp calling C++ calling Lisp
|
||||
|
||||
(in-package :eql-user)
|
||||
|
||||
(defvar *lib* (qload-c++ (in-home "Qt_EQL/eql_fun_cpp")))
|
||||
|
||||
(defun say-number (n)
|
||||
(format nil "~R" n))
|
||||
|
||||
;; see examples in "cpp_calling_lisp/lib.cpp"
|
||||
|
||||
(! "runExamples" (:qt *lib*)) ; note :qt
|
||||
|
||||
(qq)
|
||||
|
||||
4
Qt_EQL/make.bat
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
@echo off
|
||||
|
||||
cd cpp
|
||||
nmake
|
||||
30
Qt_EQL/reload.lisp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
;;;
|
||||
;;; OSX note: unloading may not work!
|
||||
;;;
|
||||
;;; Simple demo:
|
||||
;;;
|
||||
;;; 0) do: eql reload.lisp -qtpl
|
||||
;;;
|
||||
;;; 1) make some changes in "cpp/lib.h", "cpp/lib.cpp"
|
||||
;;; 2) do: (recompile-c++)
|
||||
;;; 3) goto 1)
|
||||
;;;
|
||||
;;; Call plugin functions like this:
|
||||
;;;
|
||||
;;; (qfun+ *lib* "myFunction") ; a)
|
||||
;;; (! "myFunction" (:qt *lib*)) ; b)
|
||||
;;;
|
||||
|
||||
(in-package :eql-user)
|
||||
|
||||
(defvar *lib* (qload-c++ (in-home "Qt_EQL/eql_cpp")))
|
||||
|
||||
(defun recompile-c++ ()
|
||||
(qload-c++ (in-home "Qt_EQL_dynamic/eql_cpp")
|
||||
:unload)
|
||||
(ext:run-program #+msvc "make.bat" #-msvc "make"
|
||||
#+msvc nil #-msvc '("-C" "cpp/")
|
||||
:output t)
|
||||
(setf *lib* (qload-c++ (in-home "Qt_EQL/eql_cpp")))
|
||||
(assert (qt-object-p *lib*))
|
||||
(qapropos nil *lib*))
|
||||
17
Qt_EQL/test.lisp
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
(in-package :eql-user)
|
||||
|
||||
(defvar *lib* (qload-c++ (in-home "Qt_EQL/eql_cpp")))
|
||||
|
||||
(assert (qt-object-p *lib*))
|
||||
|
||||
(qapropos nil *lib*)
|
||||
|
||||
;; test call
|
||||
|
||||
(qlet ((a "QVariant(QString)" "hello from C++")
|
||||
(b "QVariant(int)" 42)
|
||||
(c "QVariant(double)" pi)
|
||||
(d "QVariant(QByteArray)" #(69 81 76)))
|
||||
(qmsg (! "hello" (:qt *lib*) (list a b c d)))) ; note :qt
|
||||
|
||||
(qq)
|
||||
32
Qt_EQL/trafficlight/README.txt
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
This is a simple example of integrating an existing Qt/C++ application
|
||||
|
||||
|
||||
BUILD / RUN / CALL
|
||||
==================
|
||||
|
||||
qmake
|
||||
make
|
||||
|
||||
eql run.lisp -qtpl
|
||||
|
||||
________________________________________
|
||||
|
||||
Option 1:
|
||||
|
||||
(qfun+ *trafficlight* "stop")
|
||||
(qfun+ *trafficlight* "start")
|
||||
________________________________________
|
||||
|
||||
Option 2:
|
||||
|
||||
(! "stop" (:qt *trafficlight*))
|
||||
(! "start" (:qt *trafficlight*))
|
||||
________________________________________
|
||||
|
||||
Option 3:
|
||||
|
||||
(define-qt-wrappers *trafficlight*)
|
||||
|
||||
(start *trafficlight*)
|
||||
(stop *trafficlight*)
|
||||
________________________________________
|
||||
19
Qt_EQL/trafficlight/lib.cpp
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#include "lib.h"
|
||||
#include "trafficlight.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QObject* ini()
|
||||
{
|
||||
static QWidget* widget = 0;
|
||||
|
||||
if(!widget) {
|
||||
widget = new TrafficLight;
|
||||
widget->resize(110, 300);
|
||||
widget->show();
|
||||
}
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
18
Qt_EQL/trafficlight/lib.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef LIB_H
|
||||
#define LIB_H
|
||||
|
||||
#include <QtGui>
|
||||
|
||||
#ifdef Q_WS_WIN
|
||||
#define LIB_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define LIB_EXPORT
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
extern "C" { LIB_EXPORT QObject* ini(); }
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif
|
||||
23
Qt_EQL/trafficlight/run.lisp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
(in-package :eql-user)
|
||||
|
||||
(defvar *trafficlight* (qload-c++ (in-home "Qt_EQL/trafficlight/trafficlight")))
|
||||
(defvar *lights* (qfind-children *trafficlight* nil "LightWidget"))
|
||||
(defvar *red* (first *lights*))
|
||||
(defvar *yellow* (second *lights*))
|
||||
(defvar *green* (third *lights*))
|
||||
|
||||
(qapropos nil *trafficlight*)
|
||||
(qapropos nil *red*)
|
||||
|
||||
;;; generate wrappers
|
||||
|
||||
(define-qt-wrappers *trafficlight*)
|
||||
(define-qt-wrappers *red*)
|
||||
|
||||
;;; now you can do:
|
||||
;;;
|
||||
;;; (start *trafficlight*)
|
||||
;;; (stop *trafficlight*)
|
||||
;;;
|
||||
;;; (turn-on *red*)
|
||||
;;; (turn-off *green*)
|
||||
18
Qt_EQL/trafficlight/trafficlight.cpp
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// original copyright:
|
||||
//
|
||||
// ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
// ** You may use this file under the terms of the BSD license
|
||||
|
||||
#include "trafficlight.h"
|
||||
|
||||
void LightWidget::paintEvent(QPaintEvent *)
|
||||
{
|
||||
if (!m_on)
|
||||
return;
|
||||
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
painter.setBrush(m_color);
|
||||
painter.drawEllipse(0, 0, width(), height());
|
||||
}
|
||||
|
||||
134
Qt_EQL/trafficlight/trafficlight.h
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
// original copyright:
|
||||
//
|
||||
// ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
// ** You may use this file under the terms of the BSD license
|
||||
|
||||
#ifndef TRAFFICLIGHT_H
|
||||
#define TRAFFICLIGHT_H
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
class LightWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool on READ isOn WRITE setOn)
|
||||
public:
|
||||
LightWidget(const QColor &color, QWidget *parent = 0)
|
||||
: QWidget(parent), m_color(color), m_on(false) {}
|
||||
|
||||
bool isOn() const
|
||||
{ return m_on; }
|
||||
void setOn(bool on)
|
||||
{
|
||||
if (on == m_on)
|
||||
return;
|
||||
m_on = on;
|
||||
update();
|
||||
}
|
||||
|
||||
public slots:
|
||||
void turnOff() { setOn(false); }
|
||||
void turnOn() { setOn(true); }
|
||||
|
||||
protected:
|
||||
virtual void paintEvent(QPaintEvent *);
|
||||
|
||||
private:
|
||||
QColor m_color;
|
||||
bool m_on;
|
||||
};
|
||||
|
||||
class TrafficLightWidget : public QWidget
|
||||
{
|
||||
public:
|
||||
TrafficLightWidget(QWidget *parent = 0)
|
||||
: QWidget(parent)
|
||||
{
|
||||
QVBoxLayout *vbox = new QVBoxLayout(this);
|
||||
m_red = new LightWidget(Qt::red);
|
||||
m_red->setObjectName("red");
|
||||
vbox->addWidget(m_red);
|
||||
m_yellow = new LightWidget(Qt::yellow);
|
||||
m_yellow->setObjectName("yellow");
|
||||
vbox->addWidget(m_yellow);
|
||||
m_green = new LightWidget(Qt::green);
|
||||
m_green->setObjectName("green");
|
||||
vbox->addWidget(m_green);
|
||||
QPalette pal = palette();
|
||||
pal.setColor(QPalette::Background, Qt::black);
|
||||
setPalette(pal);
|
||||
setAutoFillBackground(true);
|
||||
}
|
||||
|
||||
LightWidget *redLight() const
|
||||
{ return m_red; }
|
||||
LightWidget *yellowLight() const
|
||||
{ return m_yellow; }
|
||||
LightWidget *greenLight() const
|
||||
{ return m_green; }
|
||||
|
||||
private:
|
||||
LightWidget *m_red;
|
||||
LightWidget *m_yellow;
|
||||
LightWidget *m_green;
|
||||
};
|
||||
|
||||
class TrafficLight : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
TrafficLight(QWidget *parent = 0)
|
||||
: QWidget(parent)
|
||||
{
|
||||
QVBoxLayout *vbox = new QVBoxLayout(this);
|
||||
TrafficLightWidget *widget = new TrafficLightWidget();
|
||||
vbox->addWidget(widget);
|
||||
vbox->setMargin(0);
|
||||
|
||||
machine = new QStateMachine(this);
|
||||
QState *redGoingYellow = createLightState(widget->redLight(), 2000);
|
||||
redGoingYellow->setObjectName("redGoingYellow");
|
||||
QState *yellowGoingGreen = createLightState(widget->yellowLight(), 500);
|
||||
yellowGoingGreen->setObjectName("yellowGoingGreen");
|
||||
redGoingYellow->addTransition(redGoingYellow, SIGNAL(finished()), yellowGoingGreen);
|
||||
QState *greenGoingYellow = createLightState(widget->greenLight(), 2000);
|
||||
greenGoingYellow->setObjectName("greenGoingYellow");
|
||||
yellowGoingGreen->addTransition(yellowGoingGreen, SIGNAL(finished()), greenGoingYellow);
|
||||
QState *yellowGoingRed = createLightState(widget->yellowLight(), 500);
|
||||
yellowGoingRed->setObjectName("yellowGoingRed");
|
||||
greenGoingYellow->addTransition(greenGoingYellow, SIGNAL(finished()), yellowGoingRed);
|
||||
yellowGoingRed->addTransition(yellowGoingRed, SIGNAL(finished()), redGoingYellow);
|
||||
|
||||
machine->addState(redGoingYellow);
|
||||
machine->addState(yellowGoingGreen);
|
||||
machine->addState(greenGoingYellow);
|
||||
machine->addState(yellowGoingRed);
|
||||
machine->setInitialState(redGoingYellow);
|
||||
machine->start();
|
||||
}
|
||||
|
||||
QState *createLightState(LightWidget *light, int duration, QState *parent = 0)
|
||||
{
|
||||
QState *lightState = new QState(parent);
|
||||
QTimer *timer = new QTimer(lightState);
|
||||
timer->setInterval(duration);
|
||||
timer->setSingleShot(true);
|
||||
QState *timing = new QState(lightState);
|
||||
QObject::connect(timing, SIGNAL(entered()), light, SLOT(turnOn()));
|
||||
QObject::connect(timing, SIGNAL(entered()), timer, SLOT(start()));
|
||||
QObject::connect(timing, SIGNAL(exited()), light, SLOT(turnOff()));
|
||||
QFinalState *done = new QFinalState(lightState);
|
||||
timing->addTransition(timer, SIGNAL(timeout()), done);
|
||||
lightState->setInitialState(timing);
|
||||
return lightState;
|
||||
}
|
||||
|
||||
Q_INVOKABLE void start() { machine->start(); }
|
||||
Q_INVOKABLE void stop() { machine->stop(); }
|
||||
|
||||
private:
|
||||
QStateMachine *machine;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
15
Qt_EQL/trafficlight/trafficlight.pro
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
QT += widgets
|
||||
TEMPLATE = lib
|
||||
CONFIG += plugin release
|
||||
DESTDIR = ./
|
||||
TARGET = trafficlight
|
||||
OBJECTS_DIR = ./tmp/
|
||||
MOC_DIR = ./tmp/
|
||||
|
||||
include(../../src/windows.pri)
|
||||
|
||||
HEADERS += lib.h \
|
||||
trafficlight.h
|
||||
|
||||
SOURCES += lib.cpp \
|
||||
trafficlight.cpp
|
||||
14
Qt_EQL_plugin/Qt/main.cpp
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#include <QApplication>
|
||||
#include <QWidget>
|
||||
#include "qt_application.h"
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
QApplication qapp(argc, argv);
|
||||
|
||||
MainWindow window;
|
||||
window.setGeometry(50, 50, 500, 300);
|
||||
window.show();
|
||||
|
||||
return qapp.exec();
|
||||
}
|
||||
64
Qt_EQL_plugin/Qt/qt_application.cpp
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
#include <QtWidgets>
|
||||
#include <QLibrary>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "qt_application.h"
|
||||
|
||||
typedef void (*OnShowPlugin)(QWidget*);
|
||||
typedef void (*OnHidePlugin)();
|
||||
|
||||
static OnShowPlugin onShowPlugin = 0;
|
||||
static OnHidePlugin onHidePlugin = 0;
|
||||
|
||||
MainWindow::MainWindow() : pluginWidget(0)
|
||||
{
|
||||
setWindowTitle("Qt Application");
|
||||
|
||||
QWidget* central = new QWidget;
|
||||
QLabel* label = new QLabel;
|
||||
label->setText(tr("<h3>QMainWindow with a dockable plugin widget.</h3>"));
|
||||
QPushButton* buttonShow = new QPushButton(tr("show plugin"));
|
||||
QPushButton* buttonHide = new QPushButton(tr("hide plugin"));
|
||||
setCentralWidget(central);
|
||||
|
||||
QHBoxLayout* layout = new QHBoxLayout(central);
|
||||
QVBoxLayout* buttonLayout = new QVBoxLayout;
|
||||
buttonLayout->addWidget(buttonShow);
|
||||
buttonLayout->addWidget(buttonHide);
|
||||
buttonLayout->addStretch();
|
||||
layout->addWidget(label);
|
||||
layout->addLayout(buttonLayout);
|
||||
|
||||
connect(buttonShow, SIGNAL(clicked()), SLOT(showPlugin()));
|
||||
connect(buttonHide, SIGNAL(clicked()), SLOT(hidePlugin()));
|
||||
}
|
||||
|
||||
void MainWindow::showPlugin()
|
||||
{
|
||||
static bool loaded = false;
|
||||
if(!loaded) {
|
||||
loaded = true;
|
||||
QLibrary plugin("./qt_plugin");
|
||||
onShowPlugin = (OnShowPlugin)plugin.resolve("onShowPlugin");
|
||||
onHidePlugin = (OnHidePlugin)plugin.resolve("onHidePlugin");
|
||||
pluginWidget = new QDockWidget(this);
|
||||
addDockWidget(Qt::TopDockWidgetArea, pluginWidget);
|
||||
}
|
||||
|
||||
if(onShowPlugin) {
|
||||
onShowPlugin(pluginWidget);
|
||||
}
|
||||
|
||||
pluginWidget->show();
|
||||
}
|
||||
|
||||
void MainWindow::hidePlugin()
|
||||
{
|
||||
if(pluginWidget) {
|
||||
pluginWidget->hide();
|
||||
}
|
||||
|
||||
if(onHidePlugin) {
|
||||
onHidePlugin();
|
||||
}
|
||||
}
|
||||
24
Qt_EQL_plugin/Qt/qt_application.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef QT_APPLICATION_H
|
||||
#define QT_APPLICATION_H
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWindow();
|
||||
|
||||
QDockWidget* pluginWidget;
|
||||
|
||||
public slots:
|
||||
void showPlugin();
|
||||
void hidePlugin();
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif
|
||||
10
Qt_EQL_plugin/Qt/qt_application.pro
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
QT += widgets
|
||||
TEMPLATE = app
|
||||
CONFIG += release
|
||||
TARGET = qt_application
|
||||
DESTDIR = ../
|
||||
OBJECTS_DIR = ./tmp/
|
||||
MOC_DIR = ./tmp/
|
||||
|
||||
HEADERS = qt_application.h
|
||||
SOURCES = qt_application.cpp main.cpp
|
||||
34
Qt_EQL_plugin/README.txt
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
*** N.B: MS folks: You'll need Windows >= 7 ***
|
||||
|
||||
|
||||
INTRO / DESCRIPTION
|
||||
===================
|
||||
|
||||
This is a very basic example of using EQL in a Qt plugin.
|
||||
So, if some 3rd party Qt application offers a way to integrate Qt plugins, you
|
||||
can use EQL for your plugin.
|
||||
|
||||
We assume that the 3rd party application offers us a QWidget as parent for
|
||||
our plugin. In this example it's a QDockWidget, which is bound to
|
||||
eql:*qt-main* in Lisp.
|
||||
|
||||
|
||||
|
||||
BUILD / RUN
|
||||
===========
|
||||
|
||||
- build dummy application in "Qt/"
|
||||
- build plugin in this directory
|
||||
- run the "qt_application" executable
|
||||
|
||||
|
||||
|
||||
NOTES
|
||||
=====
|
||||
|
||||
See also the function "set-data" in "ini.lisp": it shows a simple way for data
|
||||
exchange between the application and the plugin.
|
||||
It uses a dynamic Qt property, which can be accessed from both sides, C++ and
|
||||
Lisp, since the property is added to the plugin parent widget of the application:
|
||||
"pluginWidget" in C++, "*qt-main*" in Lisp.
|
||||
|
||||
49
Qt_EQL_plugin/ini.lisp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
(in-package :eql-user)
|
||||
|
||||
(defvar *label* (qnew "QLabel"))
|
||||
(defvar *edit* (qnew "QLineEdit"))
|
||||
(defvar *font* (qnew "QFont(QString,int)"
|
||||
#+darwin "Monaco" #+darwin 12
|
||||
#+linux "Monospace" #+linux 9
|
||||
#+windows "Courier New" #+windows 10))
|
||||
|
||||
(defun ini ()
|
||||
(let* ((widget (qnew "QWidget"))
|
||||
(layout (qnew "QVBoxLayout(QWidget*)" widget)))
|
||||
(dolist (w (list *label* *edit*))
|
||||
(qset w "font" *font*)
|
||||
(! "addWidget" layout w))
|
||||
(! "setWidget" *qt-main* widget)
|
||||
(qconnect *edit* "returnPressed()" 'eval-edit)
|
||||
(qlater 'delayed-ini)))
|
||||
|
||||
(defun delayed-ini ()
|
||||
(qset *edit* "text" "(in-package :eql-user)")
|
||||
(eval-edit)
|
||||
(qset *label* "text" "Enter Lisp expression and hit Return:"))
|
||||
|
||||
(defun eval-edit ()
|
||||
(qset *label* "text"
|
||||
(handler-case (let ((result (eval (read-from-string (qget *edit* "text")))))
|
||||
(! "clear" *edit*)
|
||||
(princ-to-string result))
|
||||
(error (condition)
|
||||
(x:cc "<b style='color:red'>Error:</b> " (qescape (princ-to-string condition)))))))
|
||||
|
||||
(let (loaded)
|
||||
(defun ? ()
|
||||
(unless loaded
|
||||
(setf loaded t)
|
||||
(load "../src/lisp/qselect.lisp"))
|
||||
(eql::%qselect (lambda (widget) (qset *label* "text" (format nil "~A ; see qsel:*q*" widget))))))
|
||||
|
||||
(defun set-data (data)
|
||||
"Example of using dynamic Qt properties for simple data exchange."
|
||||
(! "setProperty" *qt-main* "data"
|
||||
(typecase data
|
||||
;; 2 example cases
|
||||
(string (qnew "QVariant(QString)" data)) ; string
|
||||
(vector (qnew "QVariant(QByteArray)" data)))) ; binary data (vector of octets)
|
||||
data)
|
||||
|
||||
(ini)
|
||||
19
Qt_EQL_plugin/qt_plugin.cpp
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#include "qt_plugin.h"
|
||||
#include "eql.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
void onShowPlugin(QWidget* widget)
|
||||
{
|
||||
static EQL* eql = 0;
|
||||
if(!eql) {
|
||||
eql = new EQL;
|
||||
eql->exec(widget, "ini.lisp");
|
||||
}
|
||||
}
|
||||
|
||||
void onHidePlugin()
|
||||
{
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
23
Qt_EQL_plugin/qt_plugin.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef QT_PLUGIN_H
|
||||
#define QT_PLUGIN_H
|
||||
|
||||
#include <Qt>
|
||||
|
||||
#ifdef Q_WS_WIN
|
||||
#define LIB_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define LIB_EXPORT
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QWidget;
|
||||
|
||||
extern "C" {
|
||||
LIB_EXPORT void onShowPlugin(QWidget*);
|
||||
LIB_EXPORT void onHidePlugin();
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif
|
||||
13
Qt_EQL_plugin/qt_plugin.pro
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
TEMPLATE = lib
|
||||
CONFIG += dll no_keywords release
|
||||
INCLUDEPATH += ../src
|
||||
LIBS += -L.. -leql5
|
||||
TARGET = qt_plugin
|
||||
DESTDIR = ./
|
||||
OBJECTS_DIR = ./tmp/
|
||||
MOC_DIR = ./tmp/
|
||||
|
||||
include(../src/windows.pri)
|
||||
|
||||
HEADERS = qt_plugin.h
|
||||
SOURCES = qt_plugin.cpp
|
||||
157
README-1.txt
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
*********************************
|
||||
* EQL5 is a Qt5 port of EQL/Qt4 *
|
||||
*********************************
|
||||
|
||||
# contact: gmail, polos.ruetz
|
||||
# mailing list: http://groups.google.com/group/eql-user/topics
|
||||
#
|
||||
# MANY THANKS to the users of the eql-user mailing list for their contributions!
|
||||
|
||||
|
||||
|
||||
TESTED WITH
|
||||
===========
|
||||
|
||||
* ECL 16
|
||||
* Qt 5.5
|
||||
* Linux
|
||||
|
||||
|
||||
|
||||
REQUIREMENTS
|
||||
============
|
||||
|
||||
* ECL threads + unicode
|
||||
* Qt5
|
||||
* /should/ run cross-platform
|
||||
|
||||
|
||||
|
||||
BUILD
|
||||
=====
|
||||
|
||||
(N.B. for rebuilding, please see README-REBUILD.txt)
|
||||
|
||||
[Windows]
|
||||
You first need to adapt the file src/windows.pri (include & library paths).
|
||||
|
||||
[MSVC]
|
||||
substitute make with nmake
|
||||
|
||||
[OSX]
|
||||
To force creation of a Makefile (instead of an Xcode project), use this flag:
|
||||
qmake -spec macx-g++
|
||||
|
||||
1) In src/ run:
|
||||
|
||||
ecl -shell make-eql-lib.lisp
|
||||
|
||||
2) Do: (use qmake-qt4 if you have Qt5 installed)
|
||||
|
||||
qmake eql_lib.pro
|
||||
make
|
||||
|
||||
qmake eql_exe.pro
|
||||
make
|
||||
|
||||
This will build both the EQL executable and shared library.
|
||||
|
||||
3) cd ..
|
||||
|
||||
[Linux]
|
||||
You need to create links to EQL, something like (note the "5"):
|
||||
cd /usr/lib
|
||||
sudo ln -s ~/eql5/libeql5.so.1 libeql5.so.1
|
||||
cd /usr/bin
|
||||
sudo ln -s ~/eql5/eql5 eql5
|
||||
|
||||
[OSX]
|
||||
You need to create links to EQL, something like (note the "5"):
|
||||
cd /usr/lib
|
||||
sudo ln -s ~/eql5/libeql5.1.dylib libeql5.1.dylib
|
||||
cd /usr/bin
|
||||
sudo ln -s ~/eql5/eql5.app/Contents/MacOS/eql5 eql5
|
||||
|
||||
[Windows]
|
||||
Add your EQL directory to the Path environment variable, see:
|
||||
<Control Panel:System:Advanced:Environment Variables>
|
||||
|
||||
|
||||
|
||||
RUN
|
||||
===
|
||||
|
||||
PLEASE NOTE:
|
||||
You will often need to "reset" (command) your console/shell after EQL finished
|
||||
working, especially during development time or other exits than "(eql:qquit)".
|
||||
|
||||
|
||||
You can run a simple interactive REPL UI doing:
|
||||
eql5 -qgui
|
||||
|
||||
To run a Lisp file without top-level, do:
|
||||
eql5 examples/2-clock
|
||||
|
||||
(If you don't see the application window, it might be in the background.
|
||||
Use your taskbar to show it.)
|
||||
|
||||
If you start the EQL executable without arguments, it will start the usual ECL top-level
|
||||
(without processing Qt events).
|
||||
|
||||
To _not_ load ~/.eclrc on startup, do:
|
||||
eql5 -norc
|
||||
|
||||
To quit the tool, do:
|
||||
(eql:qquit) or
|
||||
(eql:qq)
|
||||
|
||||
In order to run (sort of) a top-level processing Qt events, do (requires ECL threads):
|
||||
eql5 -qtpl
|
||||
|
||||
Note: If you want to use "ecl-readline" together with "-qtpl", just compile
|
||||
"eql5/src/lisp/ecl-readline.lisp" (which depends on the "readline" C library).
|
||||
It will then be loaded automatically on startup.
|
||||
|
||||
|
||||
|
||||
QT MODULES (network, sql, opengl)
|
||||
==========
|
||||
|
||||
To build an EQL module (corresponding to a Qt module), do the following in src/:
|
||||
|
||||
qmake module_<name>.pro (e.g. qmake module_network.pro)
|
||||
make
|
||||
|
||||
[Linux,OSX]
|
||||
You need to create links to the modules, see EQL library above.
|
||||
|
||||
In Lisp, use the function QREQUIRE to load a module:
|
||||
(qrequire :network)
|
||||
|
||||
|
||||
|
||||
TIP
|
||||
===
|
||||
|
||||
You might want to put this in your ~/.eclrc file:
|
||||
|
||||
#+eql
|
||||
(setf eql:*qtpl* t ; same as -qtpl
|
||||
eql:*break-on-errors* t)
|
||||
|
||||
|
||||
|
||||
NOTES
|
||||
=====
|
||||
|
||||
For additional information see doc/index.html.
|
||||
|
||||
|
||||
|
||||
LICENSE
|
||||
=======
|
||||
|
||||
MIT
|
||||
|
||||
for MAKE-QIMAGE (contributed by Mark Cox), please see LICENSE-MAKE-QIMAGE.txt
|
||||
|
||||
47
README-2-REBUILD.txt
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
REBUILD STEPS (on every upgrade of: ECL, Qt, EQL)
|
||||
=============
|
||||
|
||||
Change to eql/src/ and do:
|
||||
|
||||
1) remove directory tmp/
|
||||
remove slime/thread-safe.fas*
|
||||
remove src/lisp/ecl-readline.fas* (only on upgrading ECL; to recompile manually)
|
||||
|
||||
2) ecl -shell make-eql-lib.lisp
|
||||
|
||||
3) qmake, make in this order: (MSVC: nmake; use qmake-qt4 if you have Qt5 installed)
|
||||
|
||||
eql_lib.pro
|
||||
eql_exe.pro
|
||||
|
||||
module_network.pro
|
||||
module_...
|
||||
|
||||
Optionally (integrate wrapper functions):
|
||||
|
||||
4) eql5 make-eql-lib-wrappers.lisp
|
||||
|
||||
5) re-link EQL library:
|
||||
|
||||
touch tmp/eql.o (or delete "tmp/eql.o*")
|
||||
qmake eql_lib.pro
|
||||
make
|
||||
|
||||
|
||||
IMPORTANT NOTES
|
||||
===============
|
||||
|
||||
C++:
|
||||
|
||||
You always need to rebuild from any "*.pro" file (EQL modules, Qt_EQL...) after
|
||||
upgrading EQL.
|
||||
|
||||
The simplest way to clean everything is to remove the whole "tmp/" directory in
|
||||
the respective build directory, since the Makefile generated by Qt not always
|
||||
works correctly with "make clean" (e.g. on Windows).
|
||||
|
||||
Lisp:
|
||||
|
||||
It's also recommended to recompile any compiled EQL code (because of the tight
|
||||
ECL/C++ integration).
|
||||
|
||||
51
README-3-OPTIONAL.txt
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
Wrapper functions
|
||||
=================
|
||||
|
||||
If you want to use wrapper functions for all Qt functions, see:
|
||||
|
||||
"src/lisp/all-wrappers.lisp"
|
||||
|
||||
Examples:
|
||||
|
||||
(|show| widget)
|
||||
|
||||
(|toString| (|currentTime.QTime|)) ; static function
|
||||
|
||||
(|begin(QWidget*)| painter)
|
||||
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
If you want to add the wrappers permanently, build EQL as usual, then run
|
||||
|
||||
eql5 make-eql-lib-wrappers.lisp
|
||||
|
||||
Re-link EQL doing something like:
|
||||
|
||||
touch tmp/eql.o* (or delete "tmp/eql.o*")
|
||||
qmake eql_lib.pro
|
||||
make
|
||||
|
||||
(The resulting shared library will be considerably bigger than before).
|
||||
|
||||
---
|
||||
|
||||
The convenience macro X:DO-WITH has been adapted to work with the wrappers:
|
||||
|
||||
(x:do-with item
|
||||
(|setTextAlignment| 0 |Qt.AlignRight|)
|
||||
(|setText| 0 "123"))
|
||||
|
||||
---
|
||||
|
||||
Normally not needed, but if you want to generate the wrappers for your
|
||||
Qt version (much different from Qt 5.5) do:
|
||||
|
||||
cd src/lisp
|
||||
eql5 define-all-wrappers.lisp
|
||||
|
||||
---
|
||||
|
||||
See also note in Sokoban example (no more casts needed).
|
||||
|
||||
139
doc/Debugging.htm
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="style.css" type="text/css">
|
||||
<style>
|
||||
pre { color: black; background-color: #F4F4F4; }
|
||||
code { color: black; }
|
||||
.input { color: blue; }
|
||||
</style>
|
||||
</head>
|
||||
<div style="width: 600px">
|
||||
<h2>Debugging</h2>
|
||||
This is a simple <b>tutorial</b> using the top-level processing Qt events:
|
||||
<pre>
|
||||
$ <span class="input">eql5 -qtpl</span>
|
||||
</pre>
|
||||
<br>
|
||||
<h3>Example 1: Error on REPL (trivial)</h3>
|
||||
<pre>
|
||||
|
||||
EQL-USER[1]> <span class="input">(/ 0)</span>
|
||||
|
||||
Condition of type: DIVISION-BY-ZERO
|
||||
|
||||
Available restarts:
|
||||
|
||||
1. (RESTART-TOPLEVEL) Go back to Top-Level REPL.
|
||||
2. (RESTART-QT-EVENTS) Restart Qt event processing.
|
||||
|
||||
** BREAK [LEVEL 2]>
|
||||
|
||||
</pre>
|
||||
<img src="debug-dialog.png"/>
|
||||
<p>Note that all debug input is handled in a debug dialog, <b>not</b> in the
|
||||
console window.</p>
|
||||
<p>So, either type the restart number in the dialog
|
||||
<pre><span class="input"> :r1</span></pre>
|
||||
or just click Cancel / hit Escape, which will always choose <code>:r1</code>.
|
||||
<br>Type <code>:h</code> for all available debug options.
|
||||
<p>Both restarts will have the same effect here, see note at bottom.</p>
|
||||
<br>
|
||||
<h3>Example 2: Error during Qt event processing</h3>
|
||||
Start calculator example:
|
||||
<pre>
|
||||
$ <span class="input">eql5 -qtpl examples/X-extras/calculator</span>
|
||||
</pre>
|
||||
<br>
|
||||
Let's run this function:
|
||||
<pre>
|
||||
EQL-USER[1]> <span class="input">(clc:auto "42 ? blah")</span>
|
||||
</pre>
|
||||
<br>
|
||||
This will output 2 errors, without breaking into the debugger:
|
||||
<pre>
|
||||
|
||||
[EQL:err] QFIND-CHILD #<QDialog "" 0x39737d0 [1]> "?"
|
||||
|
||||
[EQL:err] QINVOKE-METHOD NIL NIL "animateClick" (400)
|
||||
|
||||
</pre>
|
||||
<p><b>Note</b>: After eventual print output (like the above), you
|
||||
won't see a fresh top-level prompt.<br>Don't get confused by this, as
|
||||
you can continue to enter commands.</p>
|
||||
<br>
|
||||
Now make EQL errors break into the debugger:
|
||||
<pre>
|
||||
EQL-USER[2]> <span class="input">(setf eql:*break-on-errors* t)</span>
|
||||
</pre>
|
||||
<br>
|
||||
Run our function again:
|
||||
<pre>
|
||||
|
||||
EQL-USER[3]> <span class="input">(clc:auto "42 ? blah")</span>
|
||||
|
||||
Condition of type: SIMPLE-CONDITION
|
||||
|
||||
[EQL:err] QFIND-CHILD #<QDialog "" 0x39737d0 [1]> "?"
|
||||
|
||||
Available restarts:
|
||||
|
||||
1. (CONTINUE) Return from BREAK.
|
||||
2. (RESTART-QT-EVENTS) Restart Qt event processing.
|
||||
|
||||
** BREAK [LEVEL 1]>
|
||||
|
||||
</pre>
|
||||
<img src="debug-dialog.png"/>
|
||||
<p>Now there are 2 possible restarts:</p>
|
||||
<pre><span class="input"> :r1</span></pre>
|
||||
<code>(CONTINUE)</code> will continue execution, which will break on
|
||||
the next error, then finish our function.
|
||||
<pre><span class="input"> :r2</span></pre>
|
||||
<code>(RESTART-QT-EVENTS)</code> will abort execution, returning to
|
||||
the REPL immediately.
|
||||
<br><br>
|
||||
<hr>
|
||||
<br><br>
|
||||
<h3>Notes</h3>
|
||||
There is one situation where interactive debugging won't work, and
|
||||
this is in code inside an (overridden)
|
||||
<pre> "paintEvent(QPaintEvent*)"</pre> function, as this may cause
|
||||
recursive paint events and segfaults.
|
||||
<br>
|
||||
<br> <br>
|
||||
To exit instantly from EQL during debugging (on nasty errors), just type
|
||||
<pre><span class="input"> :qq</span> / <span class="input">:exit</span></pre>
|
||||
in the debug dialog (or REPL).
|
||||
<br>
|
||||
<br> <br>
|
||||
On simple <code>read</code> errors on the REPL (e.g. non-existing packages, non-external symbols), the debugger will not be entered (as this would cause an unrecoverable <code>break</code>, since <code>read</code> runs in its own thread here); instead, the erroneous input string will be returned as-is.
|
||||
<br>
|
||||
<br> <br>
|
||||
The conflicting case
|
||||
<pre> (RESTART-TOPLEVEL)
|
||||
(RESTART-QT-EVENTS)</pre>
|
||||
is resolved automatically (<code>RESTART-QT-EVENTS</code> would block the REPL in this case).
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<h3>Tips</h3>
|
||||
You might want to put this in your <code>~/.eclrc</code> file:
|
||||
<pre>
|
||||
|
||||
#+eql
|
||||
(setf eql:*qtpl* t ; same as -qtpl
|
||||
eql:*break-on-errors* t)
|
||||
|
||||
</pre>
|
||||
<br>
|
||||
<p>In order to automatically switch the REPL to a given package after loading a file, add this line:</p>
|
||||
<pre> (qlater (lambda () (in-package :my-package)))</pre>
|
||||
<br>
|
||||
<p>If you use ECL readline (see <code>ecl-readline.lisp</code> in sources):<br>After entering <code>:qq</code> (quitting the top-level), the console/shell should always be reset (but you won't probably see the command while typing it; an <code>alias</code> might help):</p>
|
||||
<pre>
|
||||
$ <span class="input">reset</span>
|
||||
</pre>
|
||||
<br>
|
||||
<br>
|
||||
</div>
|
||||
</html>
|
||||
14
doc/Deploy.htm
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="style.css" type="text/css">
|
||||
</head>
|
||||
<h2>Deploy</h2>
|
||||
<p>Please follow the <code>my_app/README.txt</code> (which assumes that your lisp files are in <code>my_app/lisp/</code>)</p>
|
||||
<p>The dependencies are:</p>
|
||||
<ul>
|
||||
<li><code>eql5</code>, <code>ecl</code>, <code>QtCore</code>, <code>QtGui</code>, <code>QtWidgets</code>, <code>QtPrintSupport</code> shared libraries
|
||||
<li>your <code>*.ui</code> files (if any)
|
||||
<li>your <code>*.qm</code> translation files (if any)
|
||||
</ul>
|
||||
A detailed description of deploying Qt applications can be found in Qt Assistant.
|
||||
</html>
|
||||
64
doc/EQL-Slime-Integration.htm
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body { font-family: sans-serif; font-size: 14px; }
|
||||
pre { background-color: #F4F4F4; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width: 700px; margin: 20px;">
|
||||
<h2>EQL (ECL + Qt) in Slime -- how does it work?</h2>
|
||||
<ul>
|
||||
<li><p>Start swank using the EQL executable, running the swank server in an ECL thread, and using the main thread for the Qt main event loop.</p>
|
||||
<li><p>Wrap every internal EQL function in a macro, which will call the function either directly (if called from GUI/main thread), or, if called from another ECL thread, will wrap the function call in a closure.</p>
|
||||
<li><p>This closure will be passed to a queued, blocking Qt function running in the GUI thread, which will in turn call the closure.</p>
|
||||
</ul>
|
||||
<p>The crucial part is passing a Lisp closure from an ECL thread to Qt and calling it from C++ in the GUI/main thread.</p>
|
||||
<p>This is trivial in ECL/Qt, since both ECL and Qt use/wrap native C threads, and Qt offers a nice utility with <code>Q_INVOKABLE</code>.</p>
|
||||
<p>First let's wrap the actual Lisp function, e.g. <code>(foo x y)</code> in a closure, so we only need to pass <b>one ECL closure pointer</b> to C++.
|
||||
<p>No need to pass Lisp arguments to C++, they are in the closure; no return value needed from C++, Lisp return values will be assigned in the closure:</p>
|
||||
<pre>
|
||||
|
||||
;; in some ECL thread
|
||||
(let (values)
|
||||
(run-in-gui-thread
|
||||
|
||||
;; in ECL main/GUI thread
|
||||
(lambda ()
|
||||
(setf values (multiple-value-list (foo x y)))))
|
||||
|
||||
;; back in some ECL thread
|
||||
(values-list values))
|
||||
|
||||
</pre>
|
||||
<p>Here the implementation of the ECL function <code>run-in-gui-thread</code> (embedded in Qt):</p>
|
||||
<pre>
|
||||
|
||||
cl_object run_in_gui_thread(cl_object closure) // define ECL function
|
||||
{
|
||||
QMetaObject::invokeMethod(
|
||||
object, // any QObject from GUI thread
|
||||
"runInGuiThread", // see Q_INVOKABLE
|
||||
Qt::BlockingQueuedConnection, // blocking for return values
|
||||
Q_ARG(void*, closure)); // 'closure' is just a pointer
|
||||
|
||||
return Cnil;
|
||||
}
|
||||
|
||||
</pre>
|
||||
<p>Now the Lisp closure will run in the GUI/main thread, and the implementation of the Qt function <code>runInGuiThread</code> is as simple as:</p>
|
||||
<pre>
|
||||
|
||||
Q_INVOKABLE void runInGuiThread(void* closure) // note Q_INVOKABLE
|
||||
{
|
||||
cl_funcall(1, (cl_object)closure); // ECL function call
|
||||
}
|
||||
|
||||
</pre>
|
||||
<p>After introducing a macro <code>qrun*</code>, and wrapping all EQL functions in it (see <nobr><code>"slime/thread-safe.lisp"</code></nobr>), we are done!</p>
|
||||
<p>(Please note that the above code is a stripped down version, see sources for the actual implementation.)</p>
|
||||
<br>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
BIN
doc/EQL.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
71
doc/Notes.htm
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="style.css" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<h2>Notes</h2>
|
||||
<p>Pass <code>-norc</code> on the command line to <b>not</b> load <code>~/.eclrc</code> on startup.<br>Since <code>:eql</code> and <code>:eql5</code> are in <code>*features*</code>, you can use e.g. <code>#+eql</code> / <code>#-eql5</code>.</p>
|
||||
<p>To run a Lisp file directly, do e.g. <code>eql5
|
||||
examples/5-colliding-mice -qtpl</code>.</p>
|
||||
<p>See the EQL UI (command <code>eql -qgui</code>) for a complete list of all
|
||||
supported classes and functions.</p>
|
||||
<p>In the above mentioned UI you find a "<b>Select</b>" button, allowing you
|
||||
to select any Qt widget (even in other main widgets), if previously loaded
|
||||
from the UI command line. After selecting a widget, the
|
||||
parameter <code>qsel:*q*</code> will be set to it.</p>
|
||||
<p>See command line option <code>-qtpl</code> for a top-level processing Qt
|
||||
events (see also <b>readline</b> note in <code>../README.txt</code>).<br>It uses a simple GUI dialog for
|
||||
debug input (needed because <code>read</code> runs in its own thread).<br>On
|
||||
eventual print output, you won't see a fresh prompt, but the REPL will
|
||||
remain ready for input.<br>You can set this option permanently by adding this in <code>~./eclrc</code>:
|
||||
<br><code>#+eql (setf eql:*qtpl* t)</code>
|
||||
</p>
|
||||
<p>If you want to use temporary Qt objects, you can use the <code>qlet</code>
|
||||
convenience macro (see the function list). It's a <code>let*</code> variant
|
||||
for Qt objects, deleting them when leaving its body.</p>
|
||||
<p>No universal GC (garbage collection) for Qt objects:
|
||||
<ul>
|
||||
<li>Qt widgets always live inside an object hierarchy, so deleting a widget
|
||||
will delete all its child widgets/objects.
|
||||
<li>For local widgets/objects, you have the <code>qlet</code> macro, which are
|
||||
deleted when leaving the <code>qlet</code> body.
|
||||
</ul>
|
||||
<ul>
|
||||
<li>So, always use <code>qlet</code> (instead of <code>qnew</code>) if you only
|
||||
need a local Qt object inside a function (e.g. <code>QDialog</code>, <code>QRegExp</code>).
|
||||
<li><b>GC</b> is implemented (using the ECL finalizer) for Qt value types (like <code>QFont</code>) returned by the functions
|
||||
<code>qget</code> and <code>qfun</code>.<br>These types are printed adding <b>GC</b>: <code>#<QFont 0x9243840 GC></code>.
|
||||
</ul>
|
||||
</p>
|
||||
<p>Enumeration example: <code>|Qt.AlignCenter|</code>.<br>So, all enumerations
|
||||
are defined as constants, using case preserving symbol names (allowing
|
||||
convenient tab completion in Emacs).
|
||||
</p>
|
||||
<p>Errors in EQL functions don't break into the debugger; if you want them to
|
||||
do so, set the variable <code>eql:*break-on-errors*</code>
|
||||
to <code>T</code>.
|
||||
<br>(So the choice is left to you: depending on the situation, either option
|
||||
may be more convenient than the other.)
|
||||
</p>
|
||||
<p>
|
||||
The currently available <b>Qt5 Modules</b> (see <code>qrequire</code>) are:
|
||||
<br><code>:network :opengl :sql</code>
|
||||
</p>
|
||||
<p>If you want to use CLOS together with <code>qt-object</code> instances
|
||||
(which are of type <code>struct</code>), see
|
||||
examples <code>X-extras/CLOS-encapsulation.lisp</code>
|
||||
and <code>5-colliding-mice.lisp</code>.<br>So there's a simple way to
|
||||
use either <code>defclass</code> or <code>defstruct</code> to
|
||||
encapsulate a <code>qt-object</code>.</p>
|
||||
<hr>
|
||||
<p>If you're interested in <b>embedding</b> EQL in existing Qt/C++ projects,
|
||||
see example in directory <code>Qt_EQL_dynamic/</code> (which can be used
|
||||
together with Slime).
|
||||
</p>
|
||||
<p>See also <b>plugin</b> example in directory <code>Qt_EQL_plugin/</code>.
|
||||
</p>
|
||||
<hr>
|
||||
<p>The necessary parsing for generating the <code>src/gen/*</code> files is
|
||||
done by parsing the Qt documentation. See <code>helper/README.txt</code> if you want do it yourself
|
||||
</body>
|
||||
</html>
|
||||
23
doc/QtDesigner.htm
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="style.css" type="text/css">
|
||||
</head>
|
||||
<h2>Qt Designer</h2>
|
||||
<ul>
|
||||
<li>In Qt Designer, set a unique <code>objectName</code> to every object you want to use from Lisp.
|
||||
<li>In Lisp, load the <code>*.ui</code> file using <code>qload-ui</code> (which will return the main widget of the UI).
|
||||
<li>To get the single widgets from the UI, use <code>qfind-child</code>.
|
||||
</ul>
|
||||
<p>For an example, see <code>examples/3-main-window.lisp</code>.</p>
|
||||
<hr>
|
||||
<p>
|
||||
If you want to translate your UI files to the corresponding EQL code, do the following
|
||||
at the command line:
|
||||
<br><code> eql -quic file.ui</code>
|
||||
<br>which will generate a file named <code>ui-file.lisp</code>. See also function <code>quic</code>.
|
||||
</p>
|
||||
<p>
|
||||
For a quick test of the generated file, try this:
|
||||
<br><code> eql ui-file.lisp</code>
|
||||
</p>
|
||||
</html>
|
||||
21
doc/QtLinguist.htm
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="style.css" type="text/css">
|
||||
</head>
|
||||
<h2>Qt Linguist</h2>
|
||||
For every new project:
|
||||
<ul>
|
||||
<li>In Lisp, wrap the strings you want to translate in the <code>tr</code> macro (as you would do in Qt), optionally passing a context and/or a plural indicator (see Qt Assistant). Both string and context can be Lisp forms evaluating to constant strings.
|
||||
<li>Adapt the <code>my_app/eql-lupdate</code> file, adding your Qt Designer <code>*.ui</code> files (if any), and listing the respective <code>*.ts</code> files for all languages you want to support.
|
||||
<li>Adapt the <code>my_app/eql-lrelease</code> file, simply listing all <code>*.ts</code> files (see above).
|
||||
</ul>
|
||||
For every new release (in order to create the <code>*.qm</code> files):
|
||||
<ul>
|
||||
<li>In <code>my_app/</code>, run <code>eql make.lisp</code> (compiling all files). This will find all source strings to translate and save them in the file <code>tr.h</code> (only a dummy needed for the Qt <code>lupdate</code> function). This is done using a compiler macro, see <code>my_app/tr.lisp</code>.</i>
|
||||
<li>Run the <code>my_app/eql-lupdate</code> script; this will create/update the single <code>*.ts</code> files for every language.
|
||||
<li>Use Qt Linguist on the <code>*.ts</code> files (as usual).
|
||||
<li>Run the <code>my_app/eql-lrelease</code> script.
|
||||
</ul>
|
||||
<p>Note: you may need to copy the respective <code>qt_*.qm</code> files (see <code>translations/</code> in the Qt sources), in order to load the translated texts used by Qt itself.</p>
|
||||
<p>See <code>my_app/main.cpp</code> for an example how to load your translation files.</p>
|
||||
</html>
|
||||
102
doc/Slime-REPL-hook.htm
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="style.css" type="text/css">
|
||||
</head>
|
||||
<h2>Slime REPL Hook</h2>
|
||||
<p>
|
||||
<p><b>Please note:</b></p>
|
||||
<p>
|
||||
You need to enable this mode manually by uncommenting this line in <code>eql-start-swank.lisp</code> in your Slime directory:
|
||||
<br> <code>(setf eql:*slime-mode* :repl-hook)</code>
|
||||
</p>
|
||||
<p>Requires <b>ECL threads</b>.</p>
|
||||
<p>
|
||||
This should work with any Slime version that plays together with ECL.
|
||||
<br>Tested with ECL 12.7.1 (Windows: ECL 12.12.1)
|
||||
</p>
|
||||
<ul>
|
||||
<h3>Prepare</h3>
|
||||
<ul>
|
||||
<li>Add to your <code>~/.emacs</code> file:
|
||||
<pre>
|
||||
(add-to-list 'load-path "~/slime/") ; slime path
|
||||
(add-to-list 'load-path "~/slime/contrib/") ; slime/contrib path
|
||||
(require 'slime)
|
||||
(slime-require 'swank-listener-hooks) ; EQL requires a listener hook
|
||||
(slime-setup '(slime-fancy))
|
||||
</pre>
|
||||
<li>Add to your <code>~/.swank.lisp</code> file (or copy file <code>eql/slime/.swank.lisp</code> in your home directory):
|
||||
<br>(Please note: this isn't really optional -- you <b>need</b> to set this option for a useful Slime + EQL.)
|
||||
<pre>
|
||||
(setf swank:*globally-redirect-io* t) ; show print output in Emacs
|
||||
</pre>
|
||||
<li>Copy file <code>eql/slime/eql-start-swank.lisp</code> in your <code>slime/</code> directory
|
||||
</ul>
|
||||
<br>
|
||||
<h3>Run</h3>
|
||||
<ul>
|
||||
<li>Run the swank server (the command line option <code>-slime</code> can be omitted if the file name contains "start-swank"), optionally passing a Lisp file:
|
||||
<pre>
|
||||
eql <path-to-slime>/eql-start-swank.lisp [file.lisp]
|
||||
</pre>
|
||||
<li>Run Emacs and do:
|
||||
<code>Meta-X slime-connect</code> (please note:
|
||||
use <code>slime-connect</code>) and hit <code>Return</code> 2 times
|
||||
(confirming the default values).
|
||||
<p>Please note: if <code>:dont-close</code> is set to <code>T</code>
|
||||
in <code>eql-start-swank.lisp</code>, quitting/restarting Emacs will not
|
||||
affect a running EQL program, that is: if you quit/restart Emacs, you can
|
||||
connect to the same swank/EQL you left when quitting Emacs.</p>
|
||||
</ul>
|
||||
<br>
|
||||
<h3>Notes</h3>
|
||||
<h4>Eval Region</h4>
|
||||
<ul>
|
||||
<li><b>Load</b> your Lisp file <b>from the Slime REPL</b>: <code>(load "file.lisp")</code>
|
||||
<li><b>Run</b> your program <b>from the Slime REPL</b> (not using Eval Region).
|
||||
<li>Only at this point you may use Eval Region for re-defining functions etc.
|
||||
</ul>
|
||||
<p>The point here is: if you directly try to Eval Region an expression containing an
|
||||
EQL function, your swank server <b>will crash</b>, because it will not be
|
||||
evaluated in the GUI thread (Qt GUI methods need to be called from the GUI thread).
|
||||
</p>
|
||||
<p>So, only run EQL functions <b>directly</b> from the <b>Slime REPL</b>.
|
||||
<br>If you want to use <b>Eval Region</b> containing EQL functions, use the
|
||||
method described above.
|
||||
</p>
|
||||
<hr>
|
||||
<p>You may use the macro <code>qeval</code> if you want to ensure evaluation
|
||||
in the GUI thread (this is meant to be used together with Eval Region only).
|
||||
<br>It behaves like a <code>progn</code>, so you can do something like this:
|
||||
<pre>
|
||||
(qeval
|
||||
(defvar *label* (qnew "QLabel"))
|
||||
(defvar *edit* (qnew "QLineEdit")))
|
||||
</pre>
|
||||
Wrapping forms in <code>qeval</code> will have no effect if you
|
||||
run your code outside of Slime (so there's no need to
|
||||
remove <code>qeval</code> in your final program).</p>
|
||||
<hr>
|
||||
<p>But note: the advantage using <b>Eval Region</b>
|
||||
(<i>without</i> <code>qeval</code>) is that Lisp error conditions (not
|
||||
driven by Qt events) will not stop/pause your EQL program (that is, Qt event
|
||||
processing will continue).</p>
|
||||
<p>Instead, if there is an error in code you either enter in the Slime REPL, or
|
||||
run with Eval Region wrapped in <code>qeval</code>, the
|
||||
program will always pause (Qt event processing will be stopped until you take some
|
||||
action).</p>
|
||||
<br>
|
||||
<h4>Abort / Restart</h4>
|
||||
<p>Be careful after entering the Slime debugger. If you see this:
|
||||
<br>
|
||||
<br><code>[ABORT] Return to SLIME's top level.</code>
|
||||
<br><code>[RESTART-QT-EVENTS] Last resort only - prefer "Return to SLIME's top level"</code>
|
||||
<br>
|
||||
<br>Always choose the first one, otherwise you'll be stuck.
|
||||
</p>
|
||||
<br>
|
||||
<h4>Help</h4>
|
||||
<p>For help see the <code>qapropos</code> and <code>qgui</code> functions.</p>
|
||||
</ul>
|
||||
<br>
|
||||
</html>
|
||||
57
doc/Slime.htm
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="style.css" type="text/css">
|
||||
</head>
|
||||
<h2>Slime</h2>
|
||||
Requires <b>ECL threads</b>.
|
||||
<p>
|
||||
This should work with any Slime version that plays together with ECL.
|
||||
<br>Tested with ECL 12.7.1 (Windows: ECL 12.12.1)
|
||||
</p>
|
||||
<br>
|
||||
<h3>Prepare</h3>
|
||||
<ul>
|
||||
<li>Add to your <code>~/.emacs</code> file:
|
||||
<pre>
|
||||
(add-to-list 'load-path "~/slime/") ; slime path
|
||||
(require 'slime)
|
||||
(slime-setup '(slime-fancy))
|
||||
</pre>
|
||||
<li>Add to your <code>~/.swank.lisp</code> file (or copy file <code>eql/slime/.swank.lisp</code> in your home directory):
|
||||
<br>(Please note: this isn't really optional -- you <b>need</b> to set this option for a useful Slime + EQL.)
|
||||
<pre>
|
||||
(setf swank:*globally-redirect-io* t) ; show print output in Emacs
|
||||
</pre>
|
||||
<li>Copy file <code>eql/slime/eql-start-swank.lisp</code> in your <code>slime/</code> directory
|
||||
</ul>
|
||||
<br>
|
||||
<h3>Run</h3>
|
||||
<ul>
|
||||
<li>Run the swank server (the command line option <code>-slime</code> can be omitted if the file name contains "start-swank"), optionally passing a Lisp file:
|
||||
<pre>
|
||||
eql <path-to-slime>/eql-start-swank.lisp [file.lisp]
|
||||
</pre>
|
||||
<li>Run Emacs and do:
|
||||
<code>Meta-X slime-connect</code> (please note:
|
||||
use <code>slime-connect</code>) and hit <code>Return</code> 2 times
|
||||
(confirming the default values).
|
||||
<p>Please note: if <code>:dont-close</code> is set to <code>T</code>
|
||||
in <code>eql-start-swank.lisp</code>, quitting/restarting Emacs will not
|
||||
affect a running EQL program, that is: if you quit/restart Emacs, you can
|
||||
connect to the same swank/EQL you left when quitting Emacs.</p>
|
||||
</ul>
|
||||
<br>
|
||||
<h3>Loading files</h3>
|
||||
<p>If you experience slow loading of files (compared to direct loading), use <code>qload</code> instead of <code>load</code>, which will reduce all thread switches during the load process to a single one.</p>
|
||||
<p>Another case where you need to use <code>qload</code> is when you use Qt classes which use threads internally (see e.g. <code>examples/X-extras/move-blocks.lisp</code>).</p>
|
||||
<br>
|
||||
<h3>Help</h3>
|
||||
<p>For help see the <code>qapropos</code> and <code>qgui</code> functions.</p>
|
||||
<p>To kill the swank process (Slime), use function <code>qquit</code> / <code>qq</code> (since quitting Emacs will not kill it).</p>
|
||||
<br>
|
||||
<h3>Notes</h3>
|
||||
<p>All EQL functions are wrapped in <code>qrun*</code> (see <code>eql/slime/thread-safe.lisp</code>), so it's safe to call them either directly from the REPL or using 'eval region' (or from any other ECL thread).</p>
|
||||
<p>This Slime mode is both convenient and simple to use, but conses a little more for every EQL function call.
|
||||
<br>If you absolutely want direct EQL function calls, please see the less convenient <a href="Slime-REPL-hook.htm">Slime REPL Hook</a> mode.</p>
|
||||
</br>
|
||||
</html>
|
||||
529
doc/auto-doc.htm
Normal file
|
|
@ -0,0 +1,529 @@
|
|||
<html><body><p>
|
||||
<b>DEFINE-QT-WRAPPERS (qt-library &rest what)</b>
|
||||
<p>Defines Lisp methods for all Qt methods/signals/slots of given library.<br>(See example <code>Qt_EQL_dynamic/trafficlight/</code>).</p>
|
||||
<pre>
|
||||
(define-qt-wrappers *c++*) ; generate wrappers (see "Qt_EQL_dynamic/")
|
||||
(define-qt-wrappers *c++* :slots) ; Qt slots only (any of :methods :slots :signals)
|
||||
|
||||
(my-qt-function *c++* x y) ; instead of: (! "myQtFunction" (:qt *c++*) x y)
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>DEFVAR-UI (main-widget &rest variables)</b>
|
||||
<p>This macro simplifies the definition of UI variables:</p>
|
||||
<pre>
|
||||
(defvar-ui *main* *label* *line-edit*...)
|
||||
|
||||
;; the above will expand to:
|
||||
|
||||
(progn
|
||||
(defvar *label* (qfind-child *main* "label"))
|
||||
(defvar *line-edit* (qfind-child *main* "line_edit"))
|
||||
...)
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>ENSURE-QT-OBJECT (object)</b>
|
||||
<p>Returns the <code>qt-object</code> of the given class/struct (see method <code>the-qt-object</code> in example <code>X-extras/CLOS-encapsulation.lisp</code>).<br>This function is used internally whenever a <code>qt-object</code> argument is expected.</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QADD-EVENT-FILTER (object event function)
</b>
|
||||
<p>Convenience function. Adds a Lisp function to be called on a given event type.<br>If the object argument is <code>NIL</code>, the event will be captured for the whole application.<br>If the Lisp function returns <code>NIL</code>, the event will be processed by Qt afterwards.<br><br>Returns a handle which can be used to remove the filter, see <code>qremove-event-filter</code>.<br><br>See also <code>qoverride</code> for <code>QObject::eventFilter(QObject*,QEvent*)</code> and <br><code>QObject::installEventFilter(QObject*)</code>,<br><code>QObject::removeEventFilter(QObject*)</code>.<br><br>The event class corresponds to the respective event type (no cast needed).
</p>
|
||||
<pre>
|
||||
(qadd-event-filter nil |QEvent.MouseButtonPress| (lambda (object mouse-event) (print object) nil))
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QAPP ()
</b>
|
||||
<p>Convenience function returning <code>qApp</code>.
</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QAPROPOS (&optional search-string class-name)
</b>
|
||||
<p>Finds all occurrencies of the given search string in the given object's meta information.<br>Constructors are listed under "Methods".<br>To list the user defined functions of external C++ classes (see Qt_EQL), pass the object instead of the class name.
</p>
|
||||
<pre>
|
||||
(qapropos "html" "QTextEdit")
|
||||
(qapropos nil "QWidget")
|
||||
(qapropos)
|
||||
(qapropos '|toString|) ; wrapper function symbol
|
||||
(qapropos nil *qt-main*) ; see Qt_EQL, Qt_EQL_dynamic (custom Qt classes, Qt3Support classes)
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QAPROPOS* (&optional search-string class-name)</b>
|
||||
<p>Similar to <code>qapropos</code>, returning the results as nested list.</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QAUTO-RELOAD-C++ (variable library-name)</b>
|
||||
<p><b>Linux only.</b><br><br>Extends <code>qload-c++</code> (see <code>Qt_EQL_dynamic/</code>).<br><br>Defines a global variable (see return value of <code>qload-c++</code>), which will be updated on every change of the C++ plugin (e.g. after recompiling, the plugin will automatically be reloaded, and the <code>variable</code> will be set to its new value).<br><br>If you want to be notified on every change of the plugin, set <code>*<variable>-reloaded*</code>. It will then be called after reloading, passing both the variable name and the plugin name.<br>See <code>qload-c++</code> for an example how to call plugin functions.</p>
|
||||
<pre>
|
||||
(qauto-reload-c++ *c++* "eql_cpp")
|
||||
|
||||
(setf *c++-reloaded* (lambda (var lib) (qapropos nil (symbol-value var)))) ; optional: set a notifier
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QCALL-DEFAULT ()
</b>
|
||||
<p>To use anywhere inside an overridden function (see <code>qoverride</code>).<br>Calls the base implementation of the virtual Qt method <b>after</b> leaving the function body.<br><br>Optionally call the base implementation directly (if you want to do post-processing of the return value).
</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QCLEAR-EVENT-FILTERS ()
</b>
|
||||
<p>Clears all added event filters.
</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QCONNECT (caller signal receiver/function &optional slot)
</b>
|
||||
<p>Connects either a Qt signal to a Qt slot, or a Qt signal to a Lisp function.
</p>
|
||||
<pre>
|
||||
(qconnect edit "textChanged(QString)" label "setText(QString)")
|
||||
(qconnect edit "textChanged(QString)" (lambda (txt) (print txt)))
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QCOPY (object)
</b>
|
||||
<p>Copies <code>object</code> using copy-on-write, if such a constructor is available (non QObject derived classes only).<br>This function is short for e.g: <code>(qnew "QPixmap(QPixmap)" pixmap)</code><br><br>Note that the returned value will not be garbage collected (analogous to <code>qnew</code>).
</p>
|
||||
<pre>
|
||||
(qcopy pixmap) ; QPen, QBrush, QFont, QPalette, QPixmap, QImage...
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QDELETE (object &optional later)
</b>
|
||||
<br>
|
||||
<b>QDEL
</b>
|
||||
<p>Deletes any Qt object, and sets the <code>pointer</code> value to <code>0</code>. Deleting a widget deletes all its child widgets, too.<br>If <code>later</code> is not <code>NIL</code>, the function <code>QObject::deleteLater()</code> will be called instead (but note: the <code>object</code> pointer will be set to <code>0</code> immediately.)<br>Returns <code>T</code> if the object has effectively been deleted.<br><br>See also <code>qlet</code> for local Qt objects.
</p>
|
||||
<pre>
|
||||
(qdel widget)
|
||||
(qdel socket :later)
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QDISCONNECT (caller &optional signal receiver/function slot)
</b>
|
||||
<p>Disconnects signals to either Qt slots or Lisp functions. Anything but the caller can be either <code>NIL</code> or omitted.<br>Returns <code>T</code> if something has effectively been disconnected.
</p>
|
||||
<pre>
|
||||
(qdisconnect edit "textChanged(QString)" label "setText(QString)")
|
||||
(qdisconnect edit "textChanged(QString)")
|
||||
(qdisconnect edit nil label)
|
||||
(qdisconnect edit)
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QENUMS (class-name &optional enum-name)
</b>
|
||||
<p>Returns the meta enum list of the given <code>class-name</code> and <code>enum-name</code> (see <code>Q_ENUMS</code> in Qt sources).<br>Omitting <code>enum-name</code> will return all meta enum lists of the class/scope.
</p>
|
||||
<pre>
|
||||
(qenums "QLineEdit" "EchoMode") ; gives '("QLineEdit" ("EchoMode" ("Normal" . 0) ...))
|
||||
(qenums "Qt")
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QEQL (object1 object2)</b>
|
||||
<p>Returns <code>T</code> for same instances of a Qt class.<br>To test for same Qt classes only, do:</p>
|
||||
<pre>
|
||||
(= (qt-object-id object1) (qt-object-id object2))
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QESCAPE (string)
</b>
|
||||
<p>Calls <code>QString::toHtmlEscaped()</code>.
</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QEVAL (&rest forms)</b>
|
||||
<p>Slime mode <code>:repl-hook</code> only (not needed in default Slime mode): evaluate forms in GUI thread. Defaults to a simple <code>progn</code> outside of Slime.</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QEXEC (&optional milliseconds)
</b>
|
||||
<p>Convenience function to call <code>QApplication::exec()</code>.<br>Optionally pass the time in milliseconds after which <code>QEventLoop::exit()</code> will be called.<br>See also <code>qsleep</code>.
</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QEXIT ()
</b>
|
||||
<p>Calls <code>QEventLoop::exit()</code>, in order to exit event processing after a call to <code>qexec</code> with a timeout.<br>Returns <code>T</code> if the event loop has effectively been exited.
</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QFIND-BOUND (&optional class-name)</b>
|
||||
<p>Finds all symbols bound to Qt objects, returning both the Qt class names and the respective Lisp variables.<br>Optionally finds the occurrencies of the passed Qt class name only.</p>
|
||||
<pre>
|
||||
(qfind-bound "QLineEdit")
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QFIND-BOUND* (&optional class-name)</b>
|
||||
<p>Like <code>qfind-bound</code>, but returning the results as list of conses.</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QFIND-CHILD (object object-name)
</b>
|
||||
<p>Calls <code>QObject::findChild<QObject*>()</code>.<br>Can be used to get the child objects of any Qt object (typically from a UI, see <code>qload-ui</code>), identified by <code>QObject::objectName()</code>.
</p>
|
||||
<pre>
|
||||
(qfind-child *main* "editor")
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QFIND-CHILDREN (object &optional object-name class-name)
</b>
|
||||
<p>Calls <code>QObject::findChildren<QObject*>()</code>, returning a list of all child objects matching <code>object-name</code> and <code>class-name</code>.<br>Omitting the <code>&optional</code> arguments will find all children, recursively.
</p>
|
||||
<pre>
|
||||
(qfind-children *qt-main* nil "LightWidget") ; see Qt_EQL example
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QFROM-UTF8 (byte-array)
</b>
|
||||
<p>Returns the byte array (vector of octets) converted using <code>QString::fromUtf8()</code>.
</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QGUI (&optional process-events)</b>
|
||||
<p>Launches the EQL convenience GUI.<br>If you don't have an interactive environment, you can pass <code>T</code> to run a pseudo Qt event loop. A better option is to start the tool like so:<br><code>eql -qgui</code>, in order to run the Qt event loop natively.</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QID (name)
</b>
|
||||
<p>Returns the internally used ID of the object name. Non QObject classes have negative ids.
</p>
|
||||
<pre>
|
||||
(qid "QWidget")
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QINVOKE-METHOD (object function-name &rest arguments)
</b>
|
||||
<br>
|
||||
<b>QFUN
</b>
|
||||
<p>Calls any of Qt methods, slots, signals. Static methods can be called by passing the string name of an object.<br><br>The most convenient way of calling Qt methods is to use the wrapper functions (see alternative 2 below), which allows for tab completion, showing all possible candidates in case of ambiguous type lists (overloaded methods). Additionally, static functions are shown as one symbol (easily catching the eye).<br><br>(Optionally you can pass the argument types (as for <code>qconnect</code> and <code>qoverride</code>), which may result in better performance, but only in some edge cases.)
</p>
|
||||
<pre>
|
||||
(qfun item "setText" 0 "Some objects are EQL.")
|
||||
(qfun "QDateTime" "currentDateTime") ; static method
|
||||
(qfun slider "valueChanged" 10) ; emit signal
|
||||
|
||||
;; alternative 1: (macro '!')
|
||||
|
||||
(! "setText" item 0 "Some objects are EQL.")
|
||||
(! "currentDateTime" "QDateTime")
|
||||
(! "valueChanged" slider 10)
|
||||
|
||||
;; alternative 2: (wrapper functions)
|
||||
|
||||
(|setText| item 0 "Some objects are EQL.")
|
||||
(|currentDateTime.QDateTime|)
|
||||
(|valueChanged| slider 10)
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QINVOKE-METHOD* (object cast-class-name function-name &rest arguments)</b>
|
||||
<br>
|
||||
<b>QFUN*</b>
|
||||
<p>Similar to <code>qinvoke-method</code>, additionally passing a class name, enforcing a cast to that class.<br>Note that this cast is not type safe (the same as a C cast, so dirty hacks are possible).<br><br>Note: using the (recommended) wrapper functions (see <code>qfun</code>), casts are applied automatically where needed.</p>
|
||||
<pre>
|
||||
(qfun* graphics-text-item "QGraphicsItem" "setPos" (list x y)) ; multiple inheritance problem
|
||||
(qfun* event "QKeyEvent" "key") ; not needed with QADD-EVENT-FILTER
|
||||
|
||||
;; alternatively:
|
||||
|
||||
(! "setPos" ("QGraphicsItem" graphics-text-item) (list x y))
|
||||
(! "key" ("QKeyEvent" event))
|
||||
|
||||
;; better/recommended:
|
||||
|
||||
(|setPos| graphics-text-item (list x y))
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QINVOKE-METHOD+ (object function-name &rest arguments)</b>
|
||||
<br>
|
||||
<b>QFUN+</b>
|
||||
<p>Use this variant to call user defined functions (declared <code>Q_INVOKABLE</code>), slots, signals from external C++ classes.<br><br>In order to call ordinary functions, slots, signals from external C++ classes, just use the ordinary <code>qfun</code>.</p>
|
||||
<pre>
|
||||
(qfun+ *qt-main* "foo") ; see Qt_EQL, Qt_EQL_dynamic
|
||||
|
||||
;; alternatively:
|
||||
|
||||
(! "foo" (:qt *qt-main*))
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QINVOKE-METHODS (object &rest functions)</b>
|
||||
<br>
|
||||
<b>QFUNS</b>
|
||||
<p>A simple syntax for nested <code>qfun</code> calls.</p>
|
||||
<pre>
|
||||
(qfuns object "funA" "funB" "funC") ; expands to: (qfun (qfun (qfun object "funA") "funB") "funC")
|
||||
(qfuns object ("funA" 1) ("funB" a b c)) ; expands to: (qfun (qfun object "funA" 1) "funB" a b c)
|
||||
(qfuns "QApplication" "font" "family")
|
||||
(qfuns *table-view* "model" ("index" 0 2) "data" "toString")
|
||||
|
||||
;; alternatively:
|
||||
|
||||
(! ("funC" "funB" "funA" object))
|
||||
(! (("funB" a b c) ("funA" 1) object))
|
||||
(! ("family" "font" "QApplication"))
|
||||
(! ("toString" "data" ("index" 0 2) "model" *table-view*))
|
||||
|
||||
;; using wrapper functions, the above reads:
|
||||
|
||||
(|funC| (|funB| (|funA| object)))
|
||||
(|funB| (|funA| object 1) a b c)
|
||||
(|family| (|font.QApplication|))
|
||||
(|toString| (|data| (|index| (|model| *table-view*) 0 2)))
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QLATER (function)</b>
|
||||
<p>Convenience macro: a <code>qsingle-shot</code> with a <code>0</code> timeout.<br>This will call <code>function</code> as soon as the Qt event loop is idle.</p>
|
||||
<pre>
|
||||
(qlater 'delayed-ini)
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QLET (((variable-1 expression-1) (variable-2 expression-2)) &body body)</b>
|
||||
<p>Similar to <code>let*</code> (and to local C++ variables).<br><br>Creates temporary Qt objects, deleting them at the end of the <code>qlet</code> body.<br>If <code>expression</code> is a string, it will be substituted with <code>(qnew expression)</code>, optionally including constructor arguments.</p>
|
||||
<pre>
|
||||
(qlet ((painter "QPainter"))
|
||||
...)
|
||||
|
||||
(qlet ((reg-exp "QRegExp(QString)" "^\\S+$"))
|
||||
...)
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QLOAD (file-name)</b>
|
||||
<p>Convenience function for Slime (or when loading EQL files from an ECL thread).<br>Loading files that create many Qt objects can be slow on the Slime REPL (many thread switches).<br>This function reduces all thread switches (GUI related) to a single one.</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QLOAD-C++
(library-name &optional unload)
</b>
|
||||
<p>Loads a custom Qt/C++ plugin (see <code>Qt_EQL_dynamic/</code>).<br>The <code>library-name</code> has to be passed as path to the plugin, without file ending.<br><br>This offers a simple way to extend your application with your own Qt/C++ functions.<br>The plugin will be reloaded (if supported by the OS) every time you call this function (Linux: see also <code>qauto-reload-c++</code>).<br>If the <code>unload</code> argument is not <code>NIL</code>, the plugin will be unloaded (if supported by the OS).
</p>
|
||||
<pre>
|
||||
(defparameter *c++* (qload-c++ "eql_cpp")) ; load (Linux: see also QAUTO-RELOAD-C++)
|
||||
|
||||
(qapropos nil *c++*) ; documentation
|
||||
|
||||
(! "mySpeedyQtFunction" (:qt *c++*)) ; call library function (note :qt)
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QLOAD-UI (file-name)
</b>
|
||||
<p>Calls a custom <code>QUiLoader::load()</code> function, loading a UI file created by Qt Designer. Returns the top level widget of the UI.<br>Use <code>qfind-child</code> to retrieve the child widgets.
</p>
|
||||
<pre>
|
||||
(qload-ui "my-fancy-gui.ui")
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QLOCAL8BIT (string)
</b>
|
||||
<p>Converts a Unicode pathname to a simple ECL base string, using <code>QString::toLocal8Bit()</code> (see <code>QLocale</code> settings).<br>Depending on the OS (namely Windows), this is necessary if you get a filename from Qt and want to use it in ECL.<br><br>See also <b>QUTF8</b>.
</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QMESSAGE-BOX (x)</b>
|
||||
<br>
|
||||
<b>QMSG</b>
|
||||
<p>Convenience function: a simple message box, converting <code>x</code> to a string if necessary.<br>Returns its argument (just like <code>print</code>).</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QNEW-INSTANCE (class-name &rest arguments/properties)
</b>
|
||||
<br>
|
||||
<b>QNEW
</b>
|
||||
<p>Creates a new Qt object, optionally passing the given arguments to the constructor.<br>Additionally you can pass any number of property/value pairs.<br>Please note how you can abbreviate long type lists.
</p>
|
||||
<pre>
|
||||
(qnew "QWidget")
|
||||
(qnew "QPixmap(int,int)" 50 50) ; constructor
|
||||
(qnew "QLabel" "text" "Readme") ; set property
|
||||
(qnew "QMatrix4x4(qreal...)" 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4)
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QNEW-INSTANCE* (class-name &rest arguments/properties)</b>
|
||||
<br>
|
||||
<b>QNEW*</b>
|
||||
<p>Convenience function for the REPL.<br>Same as <code>qnew</code>, but showing the object immediately (if of type <code>QWidget</code>).</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QNULL-OBJECT (object)</b>
|
||||
<br>
|
||||
<b>QNULL</b>
|
||||
<p>Checks for a <code>0</code> Qt object pointer.</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QOBJECT-NAMES (&optional type)
</b>
|
||||
<p>Returns all supported object names. Passing either <code>:q</code> or <code>:n</code> returns only the QObject inherited, or not QObject inherited names, respectively.
</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QOK ()
</b>
|
||||
<p>Needed to get the boolean <b>ok</b> value in cases like this:
</p>
|
||||
<pre>
|
||||
(! "getFont(bool*)" "QFontDialog" nil)
|
||||
|
||||
(|getFont.QFontDialog| nil) ; NIL needed for <bool*>
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QOVERRIDE (object name function)
</b>
|
||||
<p>Sets a Lisp function to be called on a virtual Qt method.<br>To remove a function, pass <code>NIL</code> instead of the function argument.<br><br>If you call <code>qcall-default</code> anywhere inside your overridden function, the base implementation will be called <b>afterwards</b>.<br>Instead of <code>qcall-default</code> you can directly call the base implementation, which is useful if you want to do post-processing of the returned value.
</p>
|
||||
<pre>
|
||||
(qoverride edit "keyPressEvent(QKeyEvent*)" (lambda (ev) (print (|key| ev)) (qcall-default)))
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QPROCESS-EVENTS ()
</b>
|
||||
<p>Convenience function to call <code>QApplication::processEvents()</code>.
</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QPROPERTIES (object &optional (depth 1))</b>
|
||||
<p>Prints all current properties of <code>object</code>, searching both all Qt properties and all Qt methods which don't require arguments (marked with '<b>*</b>').<br>Optionally pass a <code>depth</code> indicating how many super-classes to include. Pass <code>T</code> to include all super-classes.</p>
|
||||
<pre>
|
||||
(qproperties (|font.QApplication|))
|
||||
(qproperties (qnew "QVariant(QString)" "42"))
|
||||
(qproperties *tool-button* 2) ; depth 2: both QToolButton and QAbstractButton
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QPROPERTY (object name)
</b>
|
||||
<br>
|
||||
<b>QGET
</b>
|
||||
<p>Gets a Qt property. Enumerator values are returned as <code>int</code> values.<br>Returns <code>T</code> as second return value for successful calls.
</p>
|
||||
<pre>
|
||||
(qget label "text")
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QQUIT (&optional (exit-status 0) (kill-all-threads t))</b>
|
||||
<br>
|
||||
<b>QQ</b>
|
||||
<p>Terminates EQL. Use this function to quit gracefully, <b>not</b> <code>ext:quit</code>.</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QREMOVE-EVENT-FILTER (handle)
</b>
|
||||
<p>Removes the event filter corresponding to <code>handle</code>, which is the return value of <code>qadd-event-filter</code>.<br>Returns <code>handle</code> if the event filter has effectively been removed.<br>See also <code>qclear-event-filters</code>.
</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QREQUIRE
(module &optional quiet)
</b>
|
||||
<p>Loads an EQL module, corresponding to a Qt module.<br>Returns the module name if both loading and initializing have been successful.<br>If the <code>quiet</code> argument is not <code>NIL</code>, no error message will be shown on failure.<br><br>Currently available modules: <code>:network :opengl :sql</code>
</p>
|
||||
<pre>
|
||||
(qrequire :network)
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QRGB (red green blue &optional (alpha 255))</b>
|
||||
<p>Constructs a <code>(unsigned-byte 32)</code> value that represents a 32 bit pixel color specified by the red, green, blue and alpha values.</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QRUN-IN-GUI-THREAD (function &optional (blocking t))
</b>
|
||||
<br>
|
||||
<b>QRUN
</b>
|
||||
<p>Runs <code>function</code> in GUI thread while (by default) blocking the calling thread (if called from main thread, <code>function</code> will simply be called directly).<br>This is needed to run GUI code from ECL threads other than the main thread.<br>Returns <code>T</code> on success.<br><br>There are 2 reasons to always wrap any EQL function like this, if called from another ECL thread:<ul><li>Qt GUI methods always need to run in the GUI thread<li>EQL functions are not designed to be reentrant (not needed for GUI code)</ul>See also macro <code>qrun*</code>.
</p>
|
||||
<pre>
|
||||
(qrun 'update-view-data)
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QRUN-IN-GUI-THREAD* (&body body)</b>
|
||||
<br>
|
||||
<b>QRUN*</b>
|
||||
<p>Convenience macro for <code>qrun</code>, wrapping <code>body</code> in a closure (passing arguments, return values).</p>
|
||||
<pre>
|
||||
(qrun* (|setValue| ui:*progress-bar* value))
|
||||
|
||||
(let ((item (qrun* (qnew "QTableWidgetItem")))) ; return value(s)
|
||||
...)
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QSELECT (&optional on-selected)</b>
|
||||
<br>
|
||||
<b>QSEL</b>
|
||||
<p>Allows to select (by clicking) any (child) widget.<br>The variable <code>qsel:*q*</code> is set to the latest selected widget.<br><br>Optionally pass a function to be called upon selecting, with the selected widget as argument.</p>
|
||||
<pre>
|
||||
(qsel (lambda (widget) (qmsg widget)))
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QSENDER ()
</b>
|
||||
<p>Corresponding to <code>QObject::sender()</code>. To use inside a Lisp function connected to a Qt signal.
</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QSET-COLOR (widget color-role color)</b>
|
||||
<p>Convenience function for simple color settings (avoiding <code>QPalette</code> boilerplate).<br>Use <code>QPalette</code> directly for anything more involved.</p>
|
||||
<pre>
|
||||
(qset-color widget |QPalette.Window| "white")
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QSET-NULL (object)</b>
|
||||
<p>Sets the Qt object pointer to <code>0</code>. This function is called automatically after <code>qdel</code>.</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QSET-PROPERTY (object name value)
</b>
|
||||
<br>
|
||||
<b>QSET
</b>
|
||||
<p>Sets a Qt property. Enumerators have to be passed as <code>int</code> values.<br>Returns <code>T</code> as second return value for successful calls.
</p>
|
||||
<pre>
|
||||
(qset label "alignment" |Qt.AlignCenter|)
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QSIGNAL (name)</b>
|
||||
<p>Needed in functions which expect a <code>const char*</code> Qt signal (not needed in <code>qconnect</code>).</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QSINGLE-SHOT (milliseconds function)
</b>
|
||||
<p>A single shot timer similar to <code>QTimer::singleShot()</code>.
</p>
|
||||
<pre>
|
||||
(qsingle-shot 1000 'one-second-later)
|
||||
|
||||
(let ((ms 500))
|
||||
(qsingle-shot ms (lambda () (qmsg ms))))
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QSLEEP (seconds)</b>
|
||||
<p>Similar to <code>sleep</code>, but continuing to process Qt events.</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QSLOT (name)</b>
|
||||
<p>Needed in functions which expect a <code>const char*</code> Qt slot (not needed in <code>qconnect</code>).</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QSTATIC-META-OBJECT (class-name)
</b>
|
||||
<p>Returns the <code>::staticMetaObject</code> of the given class name.
</p>
|
||||
<pre>
|
||||
(qstatic-meta-object "QEasingCurve")
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QSUPER-CLASS-NAME (name)
</b>
|
||||
<p>Returns the super class of an object name, or <code>NIL</code> if the class doesn't inherit another Qt class.<br>Returns <code>T</code> as second return value for successful calls.
</p>
|
||||
<pre>
|
||||
(qsuper-class-name "QGraphicsLineItem")
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QT-OBJECT-?
(object)
</b>
|
||||
<p>Returns the specific <code>qt-object</code> of a generic <code>qt-object</code>.<br>Works for QObject and QEvent inherited classes only.
</p>
|
||||
<pre>
|
||||
(qt-object-? (|parentWidget| widget))
|
||||
(qt-object-? (|widget| (|itemAt| box-layout 0)))
|
||||
(qt-object-? event)
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QT-OBJECT-NAME (object)
</b>
|
||||
<p>Returns the Qt class name.
</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QUI-CLASS (file-name &optional object-name)
</b>
|
||||
<p>Finds the class name for the given user-defined object name in the given UI file.<br>Omitting the object name will return the top level class name of the UI.
</p>
|
||||
<pre>
|
||||
(qui-class "examples/data/main-window.ui" "editor") ; returns "QTextEdit"
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QUI-NAMES (file-name)
</b>
|
||||
<p>Finds all user-defined object names in the given UI file.
</p>
|
||||
<pre>
|
||||
(qui-names "examples/data/main-window.ui")
|
||||
</pre>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QUIC (&optional (file.h "ui.h") (file.lisp "ui.lisp") (ui-package :ui))</b>
|
||||
<p>Takes C++ code from a file generated by the <code>uic</code> user interface compiler, and generates the corresponding EQL code.<br>See also command line option <code>-quic</code>.</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QUTF8 (string)
</b>
|
||||
<p>Converts a Unicode pathname to a simple ECL base string, using <code>QString::toUtf8()</code>.<br>Depending on the OS (namely OSX, Linux), this is necessary if you get a filename from Qt and want to use it in ECL.<br><br>See also <b>QLOCAL8BIT</b>.
</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>QVERSION ()
</b>
|
||||
<p>Returns the EQL version number as "<year>.<month>.<counter>", analogous to the ECL version number.<br>The second return value is the Qt version as returned by <code>qVersion()</code>.
</p>
|
||||
</p><br>
|
||||
<p>
|
||||
<b>TR (source &optional context plural-number)</b>
|
||||
<p>Macro expanding to <code>qtranslate</code>, which calls <code>QCoreApplication::translate()</code>.<br>Both <code>source</code> and <code>context</code> can be Lisp forms evaluating to constant strings (at compile time).<br>The <code>context</code> argument defaults to the Lisp file name. For the <code>plural-number</code>, see Qt Assistant.</p>
|
||||
</p><br>
|
||||
</body></html>
|
||||
78
doc/auto-doc.lisp
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
;;; copyright (c) 2010-2013 Polos Ruetz
|
||||
|
||||
(in-package :eql-user)
|
||||
|
||||
(defparameter *help* nil)
|
||||
|
||||
(defun add-cpp-docu ()
|
||||
(with-open-file (s (eql:in-home "src/ecl_fun.cpp") :direction :input)
|
||||
(let (curr ex)
|
||||
(flet ((add-curr ()
|
||||
(when curr
|
||||
(push (reverse curr) *help*)
|
||||
(setf curr nil)))
|
||||
(trim (str)
|
||||
(string-trim '(#\/ #\Space) str)))
|
||||
(x:while-it (read-line s nil nil)
|
||||
(let ((line (string-trim " " x:it)))
|
||||
(when (x:starts-with "///" line)
|
||||
(when (x:starts-with "cl_object " ex)
|
||||
(add-curr)
|
||||
(let* ((pos (search "///" ex :start2 3)) ; exception: Lisp name at end of line
|
||||
(fun (if pos
|
||||
(trim (subseq ex (+ 3 pos)))
|
||||
(trim (subseq ex 10)))))
|
||||
(push (if pos
|
||||
fun
|
||||
(substitute #\- #\_ (string-trim "2" (subseq fun 0 (position #\( fun)))))
|
||||
curr)))
|
||||
(push (trim line) curr))
|
||||
(setf ex line)))
|
||||
(add-curr)))))
|
||||
|
||||
(defun add-lisp-docu ()
|
||||
(do-external-symbols (sym (find-package :eql))
|
||||
(let ((name (symbol-name sym)))
|
||||
(when (or (char= #\Q (char name 0))
|
||||
(find name '("ENSURE-QT-OBJECT" "DEFINE-QT-WRAPPERS" "DEFVAR-UI" "TR") :test 'string=))
|
||||
(x:when-it (documentation sym 'function)
|
||||
(let ((fun (string-downcase (symbol-name sym)))
|
||||
(docu (mapcar #'(lambda (s) (string-trim " " s)) (x:split x:it #\Newline))))
|
||||
(unless (string= fun (subseq (second docu) 7))
|
||||
(push (cons fun docu) *help*))))))))
|
||||
|
||||
(defun help ()
|
||||
(setf *help* nil)
|
||||
(add-cpp-docu)
|
||||
(add-lisp-docu)
|
||||
(with-open-file (s (eql:in-home "doc/auto-doc.htm") :direction :output :if-exists :supersede)
|
||||
(write-string "<html><body>" s)
|
||||
(flet ((el (tag x)
|
||||
(format nil "<~A>~A</~A>" tag x tag))
|
||||
(! (x)
|
||||
(format s "~A~%" x))
|
||||
(tab ()
|
||||
(write-string " " s)))
|
||||
(setf *help* (sort *help* #'string< :key #'first))
|
||||
(dolist (curr *help*)
|
||||
(! "<p>")
|
||||
(! (el "b" (format nil "~A ~A" (string-upcase (first curr)) (subseq (second curr) 6))))
|
||||
(let ((n 2))
|
||||
(when (x:starts-with "alias:" (third curr))
|
||||
(incf n)
|
||||
(! "<br>")
|
||||
(! (el "b" (string-upcase (subseq (third curr) 7)))))
|
||||
(! (el "p" (nth n curr)))
|
||||
(let ((examples (nthcdr (1+ n) curr)))
|
||||
(when examples
|
||||
(! "<pre>")
|
||||
(dolist (example examples)
|
||||
(tab)
|
||||
(! example))
|
||||
(! "</pre>"))))
|
||||
(! "</p><br>"))
|
||||
(write-string "</body></html>" s))))
|
||||
|
||||
(progn
|
||||
(help)
|
||||
(eql:qq))
|
||||
BIN
doc/debug-dialog.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
18
doc/index.html
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="style.css" type="text/css">
|
||||
</head>
|
||||
<body style="margin-left: 25px;">
|
||||
<img src="EQL.png">
|
||||
<ul>
|
||||
<li><a href="auto-doc.htm">Function List</a>
|
||||
<li><a href="Slime.htm">Slime</a>
|
||||
<li><a href="Debugging.htm">Debugging</a>
|
||||
<li><a href="QtDesigner.htm">Qt Designer</a>
|
||||
<li><a href="QtLinguist.htm">Qt Linguist</a>
|
||||
<li><a href="Deploy.htm">Deploy</a>
|
||||
<li><a href="Notes.htm">Notes</a>
|
||||
</ul>
|
||||
<p><a href="http://groups.google.com/d/forum/eql-user">Mailing List (Google Groups)</a></p>
|
||||
</body>
|
||||
</html>
|
||||
5
doc/style.css
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
a:link { text-decoration: none; color: blue; }
|
||||
a:hover, a:visited, a:visited:hover { text-decoration: underline; color: blue; }
|
||||
body { font-family: sans-serif; font-size: 10pt; }
|
||||
code, pre { color: mediumblue; }
|
||||
.added { color: red; }
|
||||
8
examples/0-Tutorial/0.lisp
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
;; Lisp versus C++ (note reversed order)
|
||||
|
||||
(|currentTime.QTime|) ; QTime::currentTime()
|
||||
|
||||
(|toString| (|currentTime.QTime|)) ; QTime::currentTime().toString()
|
||||
|
||||
(|toString| (|addSecs| (|currentTime.QTime|) 1000)) ; QTime::currentTime().addSecs(1000).toString()
|
||||
|
||||
11
examples/0-Tutorial/1.lisp
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#-qt-wrapper-functions ; see README-OPTIONAL.txt
|
||||
(load (in-home "src/lisp/all-wrappers"))
|
||||
|
||||
;;; Ported Qt Widgets Tutorial - Creating a Window
|
||||
|
||||
(in-package :eql-user)
|
||||
|
||||
(let ((window (qnew "QWidget"
|
||||
"size" '(320 240)
|
||||
"windowTitle" "Top-level widget")))
|
||||
(|show| window))
|
||||
15
examples/0-Tutorial/2.lisp
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#-qt-wrapper-functions ; see README-OPTIONAL.txt
|
||||
(load (in-home "src/lisp/all-wrappers"))
|
||||
|
||||
;;; Ported Qt Widgets Tutorial - Child Widgets
|
||||
|
||||
(in-package :eql-user)
|
||||
|
||||
(let ((window (qnew "QWidget"
|
||||
"size" '(320 240)
|
||||
"windowTitle" "Child widget"))
|
||||
(button (qnew "QPushButton"
|
||||
"text" "Press me"
|
||||
"pos" '(100 100))))
|
||||
(|setParent| button window)
|
||||
(|show| window))
|
||||
17
examples/0-Tutorial/3.lisp
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#-qt-wrapper-functions ; see README-OPTIONAL.txt
|
||||
(load (in-home "src/lisp/all-wrappers"))
|
||||
|
||||
;;; Ported Qt Widgets Tutorial - Using Layouts
|
||||
|
||||
(in-package :eql-user)
|
||||
|
||||
(let ((window (qnew "QWidget"
|
||||
"windowTitle" "Window layout"))
|
||||
(label (qnew "QLabel"
|
||||
"text" "Name:"))
|
||||
(line-edit (qnew "QLineEdit"))
|
||||
(layout (qnew "QHBoxLayout")))
|
||||
(dolist (w (list label line-edit))
|
||||
(|addWidget| layout w))
|
||||
(|setLayout| window layout)
|
||||
(|show| window))
|
||||
44
examples/0-Tutorial/4.lisp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#-qt-wrapper-functions
|
||||
(load (in-home "src/lisp/all-wrappers"))
|
||||
|
||||
;;; Ported Qt Widgets Tutorial - Nested Layouts
|
||||
|
||||
(in-package :eql-user)
|
||||
|
||||
(defun start ()
|
||||
(let ((window (qnew "QWidget"
|
||||
"windowTitle" "Nested layouts"))
|
||||
(query-label (qnew "QLabel"
|
||||
"text" "Query:"))
|
||||
(query-edit (qnew "QLineEdit"))
|
||||
(result-view (qnew "QTableView"))
|
||||
(query-layout (qnew "QHBoxLayout"))
|
||||
(main-layout (qnew "QVBoxLayout")))
|
||||
(dolist (w (list query-label query-edit))
|
||||
(|addWidget| query-layout w))
|
||||
(|addLayout| main-layout query-layout)
|
||||
(|addWidget| main-layout result-view)
|
||||
(|setLayout| window main-layout)
|
||||
(setup-model-and-view result-view)
|
||||
(|show| window)))
|
||||
|
||||
(defun setup-model-and-view (view)
|
||||
(let ((model (qnew "QStandardItemModel")))
|
||||
(|setHorizontalHeaderLabels| model '("Name" "Office"))
|
||||
(dolist (row '(("Verne Nilsen" "123")
|
||||
("Carlos Tang" "77")
|
||||
("Bronwyn Hawcroft" "119")
|
||||
("Alessandro Hanssen" "32")
|
||||
("Andrew John Bakken" "54")
|
||||
("Vanessa Weatherley" "85")
|
||||
("Rebecca Dickens" "17")
|
||||
("David Bradley" "42")
|
||||
("Knut Walters" "25")
|
||||
("Andrea Jones" "34")))
|
||||
(|appendRow| model (loop :for text :in row
|
||||
:collect (qnew "QStandardItem(QString)" text))))
|
||||
(|setModel| view model)
|
||||
(|hide| (|verticalHeader| view))
|
||||
(|setStretchLastSection| (|horizontalHeader| view) t)))
|
||||
|
||||
(start)
|
||||
10
examples/1-hello-world.lisp
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#-qt-wrapper-functions ; see README-OPTIONAL.txt
|
||||
(load (in-home "src/lisp/all-wrappers"))
|
||||
|
||||
;;; hello world
|
||||
|
||||
(in-package :eql-user)
|
||||
|
||||
(qnew* "QLabel" ; QNEW* is QNEW followed by |show|
|
||||
"text" "<h1>hello world</h1>"
|
||||
"pos" '(50 50))
|
||||
94
examples/2-clock.lisp
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
;;; This is (kind of) a port of the Qt Script Example "Clock"
|
||||
|
||||
#-qt-wrapper-functions ; see README-OPTIONAL.txt
|
||||
(load (in-home "src/lisp/all-wrappers"))
|
||||
|
||||
(defpackage :clock
|
||||
(:use :common-lisp :eql)
|
||||
(:export
|
||||
#:*clock*
|
||||
#:start))
|
||||
|
||||
(in-package :clock)
|
||||
|
||||
(defparameter *show-seconds* t)
|
||||
(defparameter *show-minutes* t)
|
||||
|
||||
(defvar *clock* (qnew "QWidget(QWidget*,Qt::WindowFlags)" nil |Qt.WindowStaysOnTopHint|
|
||||
"size" '(170 170)
|
||||
"pos" '(50 50)))
|
||||
|
||||
(defun start ()
|
||||
(let ((timer (qnew "QTimer(QObject*)" *clock*)))
|
||||
(qconnect timer "timeout()" (lambda () (|update| *clock*)))
|
||||
(qoverride *clock* "paintEvent(QPaintEvent*)" 'paint)
|
||||
(|start| timer 500)
|
||||
(x:do-with *clock* |show| |raise|)))
|
||||
|
||||
(defun pen (width &optional (color "black"))
|
||||
(x:let-it (qnew "QPen")
|
||||
(x:do-with x:it
|
||||
(|setCapStyle| |Qt.RoundCap|)
|
||||
(|setWidth| width)
|
||||
(|setColor| color))))
|
||||
|
||||
(defun brush (color)
|
||||
(x:let-it (qnew "QBrush")
|
||||
(x:do-with x:it
|
||||
(|setStyle| |Qt.SolidPattern|)
|
||||
(|setColor| color))))
|
||||
|
||||
(defparameter *pen-clock* (pen 8 "steelblue"))
|
||||
(defparameter *pen-hour-marks* (pen 4))
|
||||
(defparameter *pen-minute-marks* (pen 2 "steelblue"))
|
||||
(defparameter *pen-hour* (pen 7))
|
||||
(defparameter *pen-minute* (pen 5))
|
||||
(defparameter *pen-second* (pen 2 "red"))
|
||||
(defparameter *brush-clock* (brush "white"))
|
||||
(defparameter *brush-second* (brush "gold"))
|
||||
|
||||
(defun paint (ev)
|
||||
(macrolet ((with-save (() &body body)
|
||||
`(progn (|save| p) ,@body (|restore| p))))
|
||||
(qlet ((p "QPainter(QWidget*)" *clock*))
|
||||
(let* ((size (|size| *clock*))
|
||||
(scale (/ (apply 'min size) 170)))
|
||||
(|translate| p (mapcar (lambda (x) (/ x 2)) size))
|
||||
(|scale| p scale scale))
|
||||
(|rotate| p -90)
|
||||
(|setRenderHint| p |QPainter.Antialiasing|)
|
||||
(|setPen| p *pen-clock*)
|
||||
(|setBrush| p *brush-clock*)
|
||||
(|drawEllipse| p '(-75 -75 150 150))
|
||||
(|setPen| p *pen-hour-marks*)
|
||||
(dotimes (n 12)
|
||||
(|rotate| p 30)
|
||||
(|drawLine| p '(55 0 65 0)))
|
||||
(|setPen| p *pen-minute-marks*)
|
||||
(dotimes (n 60)
|
||||
(|rotate| p 6)
|
||||
(|drawLine| p '(63 0 65 0)))
|
||||
(multiple-value-bind (sec min hour)
|
||||
(get-decoded-time)
|
||||
(with-save ()
|
||||
(|rotate| p (+ (* 30 hour) (/ min 2)))
|
||||
(|setPen| p *pen-hour*)
|
||||
(|setOpacity| p 0.5)
|
||||
(|drawLine| p '(-10 0 36 0)))
|
||||
(when *show-minutes*
|
||||
(with-save ()
|
||||
(|rotate| p (* 6 min))
|
||||
(|setPen| p *pen-minute*)
|
||||
(|setOpacity| p 0.5)
|
||||
(|drawLine| p '(-15 0 65 0))))
|
||||
(when *show-seconds*
|
||||
(with-save ()
|
||||
(|rotate| p (* 6 sec))
|
||||
(|setPen| p *pen-second*)
|
||||
(|setBrush| p *brush-second*)
|
||||
(|drawEllipse| p '(-1.5 -1.5 3 3))
|
||||
(|setOpacity| p 0.7)
|
||||
(|drawLine| p '(-15 0 52 0))
|
||||
(|drawEllipse| p '(53 -4 8 8))))))))
|
||||
|
||||
(start)
|
||||
55
examples/3-main-window.lisp
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
#-qt-wrapper-functions ; see README-OPTIONAL.txt
|
||||
(load (in-home "src/lisp/all-wrappers"))
|
||||
|
||||
(defpackage :main-window
|
||||
(:use :common-lisp :eql)
|
||||
(:export
|
||||
#:start))
|
||||
|
||||
(in-package :main-window)
|
||||
|
||||
(defvar *main* (qload-ui (in-home "examples/data/main-window.ui")))
|
||||
(defvar *editor* (qfind-child *main* "editor"))
|
||||
(defvar *action-open* (qfind-child *main* "action_open"))
|
||||
(defvar *action-save* (qfind-child *main* "action_save"))
|
||||
|
||||
(defun os-pathname (name)
|
||||
"Needed because ECL uses base strings (not Unicode) for pathnames internally."
|
||||
#+(or darwin linux)
|
||||
(qutf8 name)
|
||||
#+win32
|
||||
(qlocal8bit name))
|
||||
|
||||
(defun read-file (file)
|
||||
(with-open-file (s (os-pathname file) :direction :input)
|
||||
(let ((str (make-string (file-length s))))
|
||||
(read-sequence str s)
|
||||
str)))
|
||||
|
||||
(defun set-icon (action name)
|
||||
(|setIcon| action (qnew "QIcon(QString)"
|
||||
(in-home (format nil "examples/data/icons/~A.png" name)))))
|
||||
|
||||
(defun start ()
|
||||
(x:do-with (qset *main*)
|
||||
("pos" '(50 50))
|
||||
("size" '(700 500)))
|
||||
(set-icon *action-open* "open")
|
||||
(set-icon *action-save* "save")
|
||||
(qconnect *action-open* "triggered()" 'file-open)
|
||||
(qconnect *action-save* "triggered()" 'file-save)
|
||||
(|setHtml| *editor* (read-file (in-home "examples/data/utf8.htm")))
|
||||
(x:do-with *main* |show| |raise|))
|
||||
|
||||
(defun file-open ()
|
||||
(let ((file (|getOpenFileName.QFileDialog|)))
|
||||
(unless (x:empty-string file)
|
||||
(|setHtml| *editor* (read-file file)))))
|
||||
|
||||
(defun file-save ()
|
||||
(let ((file (|getSaveFileName.QFileDialog|)))
|
||||
(unless (x:empty-string file)
|
||||
(with-open-file (s (os-pathname file) :direction :output :if-exists :supersede)
|
||||
(write-string (|toHtml| *editor*) s)))))
|
||||
|
||||
(start)
|
||||
70
examples/4-wiggly-widget.lisp
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
;;; This is a port of the Qt Example "Wiggly Widget"
|
||||
|
||||
#-qt-wrapper-functions ; see README-OPTIONAL.txt
|
||||
(load (in-home "src/lisp/all-wrappers"))
|
||||
|
||||
(defpackage :wiggly-widget
|
||||
(:nicknames :wiggly)
|
||||
(:use :common-lisp :eql)
|
||||
(:export
|
||||
#:start))
|
||||
|
||||
(in-package :wiggly-widget)
|
||||
|
||||
(defparameter *curve* #.(coerce (loop :for i :below 16 :collect (round (* 100 (sin (* i (/ pi 8))))))
|
||||
'vector)
|
||||
"Vector of 16 values ranging from -100 to 100.")
|
||||
|
||||
(defvar *wiggly* (qnew "QWidget"
|
||||
"font" (x:let-it (|font.QApplication|)
|
||||
(|setPointSize| x:it (+ 20 (|pointSize| x:it))))
|
||||
"autoFillBackground" t))
|
||||
|
||||
(defvar *edit* (qnew "QLineEdit" "alignment" |Qt.AlignCenter|))
|
||||
(defvar *timer* (qnew "QTimer"))
|
||||
|
||||
(defparameter *step* 0)
|
||||
|
||||
(defun start ()
|
||||
(|setBackgroundRole| *wiggly* |QPalette.Light|)
|
||||
(let ((dlg (qnew "QDialog" "size" '(600 200)))
|
||||
(vbox (qnew "QVBoxLayout")))
|
||||
(|setLayout| dlg vbox)
|
||||
(dolist (w (list *wiggly* *edit*))
|
||||
(|addWidget| vbox w))
|
||||
(qconnect *timer* "timeout()" 'timeout)
|
||||
(qoverride *wiggly* "paintEvent(QPaintEvent*)" 'paint)
|
||||
(|start| *timer* 50)
|
||||
(|setText| *edit* "= never odd or even =")
|
||||
(x:do-with dlg |show| |raise|)))
|
||||
|
||||
(defun paint (ev)
|
||||
(qlet ((painter "QPainter(QWidget*)" *wiggly*) ; local QPainter variable: no need to call "begin", "end"
|
||||
(pen "QPen")
|
||||
(metrics "QFontMetrics(QFont)" (|font| *wiggly*)))
|
||||
(let* ((txt (|text| *edit*))
|
||||
(x (/ (- (|width| *wiggly*)
|
||||
(|width| metrics txt))
|
||||
2))
|
||||
(y (/ (- (+ (|height| *wiggly*) (|ascent| metrics))
|
||||
(|descent| metrics))
|
||||
2))
|
||||
(h (|height| metrics)))
|
||||
(dotimes (i (length txt))
|
||||
(let ((ix (mod (+ i *step*) 16))
|
||||
(ch (char txt i)))
|
||||
(|setColor| pen (|fromHsv.QColor| (* 16 (- 15 ix)) 255 191))
|
||||
(x:do-with painter
|
||||
(|setPen| pen)
|
||||
(|drawText| (list (floor x)
|
||||
(floor (- y (/ (* h (svref *curve* ix)) 400))))
|
||||
(string ch)))
|
||||
(incf x (|width| metrics ch)))))))
|
||||
|
||||
(defun timeout ()
|
||||
(incf *step*)
|
||||
(|update| *wiggly*))
|
||||
|
||||
(progn
|
||||
(start)
|
||||
(qlater (lambda () (in-package :wiggly))))
|
||||
248
examples/5-colliding-mice.lisp
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
;;; This is a port of the Qt Example "Colliding Mice"
|
||||
;;;
|
||||
;;; Note (OSX only):
|
||||
;;;
|
||||
;;; Seldom crashes (OSX 10.4, Qt 4.6.2) are not related to this tool, as they happen even in the original Qt example.
|
||||
;;;
|
||||
;;; The good news: if a seg.fault happens (in C++), just choose the restart option "Abort" (below "Continue"),
|
||||
;;; and the application will continue to run.
|
||||
|
||||
#-qt-wrapper-functions ; see README-OPTIONAL.txt
|
||||
(load (in-home "src/lisp/all-wrappers"))
|
||||
|
||||
(defpackage :colliding-mice
|
||||
(:nicknames :mice)
|
||||
(:use :common-lisp :eql)
|
||||
(:export
|
||||
#:start))
|
||||
|
||||
(in-package :colliding-mice)
|
||||
|
||||
(defconstant +2pi+ (* 2 pi))
|
||||
|
||||
(defvar *graphics-scene* (qnew "QGraphicsScene"
|
||||
"sceneRect" '(-300 -300 600 600)))
|
||||
(defvar *timer* (qnew "QTimer"))
|
||||
(defvar *mouse-count* 0)
|
||||
|
||||
(defstruct mouse ; DEFSTRUCT (instead of DEFCLASS) is simpler in this case
|
||||
(item (qnew "QGraphicsItem"))
|
||||
(brush (brush (|fromRgb.QColor| (random 256) (random 256) (random 256))))
|
||||
(angle 0)
|
||||
(speed 0)
|
||||
(eye-direction 0))
|
||||
|
||||
(defmethod the-qt-object ((object mouse)) ; see example "X-extras/CLOS-encapsulation.lisp"
|
||||
(mouse-item object))
|
||||
|
||||
(let ((shape (x:let-it (qnew "QPainterPath")
|
||||
(|addRect| x:it '(-10 -20 20 40)))))
|
||||
(defun new-mouse ()
|
||||
(incf *mouse-count*)
|
||||
(let ((mouse (make-mouse)))
|
||||
(|setRotation| mouse (random (* 360 16)))
|
||||
(x:do-with (qoverride mouse)
|
||||
("boundingRect()"
|
||||
(lambda () '(-18.5 -22.5 36.5 60.5)))
|
||||
("shape()"
|
||||
(lambda () shape))
|
||||
("paint(QPainter*,QStyleOptionGraphicsItem*,QWidget*)"
|
||||
(lambda (painter s w) (paint mouse painter)))
|
||||
("advance(int)"
|
||||
(lambda (step) (advance mouse step))))
|
||||
mouse)))
|
||||
|
||||
(defun brush (color &optional (style |Qt.SolidPattern|))
|
||||
(x:let-it (qnew "QBrush")
|
||||
(|setStyle| x:it style)
|
||||
(when color
|
||||
(|setColor| x:it color))))
|
||||
|
||||
(defparameter *brush-eyes* (brush "white"))
|
||||
(defparameter *brush-nose* (brush "black"))
|
||||
(defparameter *brush-ears* (brush "olive"))
|
||||
(defparameter *brush-colliding* (brush "red"))
|
||||
(defparameter *brush-tail* (brush nil |Qt.NoBrush|))
|
||||
|
||||
(defparameter *painter-path-tail* (x:let-it (qnew "QPainterPath")
|
||||
(x:do-with x:it
|
||||
(|moveTo| '(0 20))
|
||||
(|cubicTo| '(-5 22) '(-5 22) '(0 25))
|
||||
(|cubicTo| '(5 27) '(5 32) '(0 30))
|
||||
(|cubicTo| '(-5 32) '(-5 42) '(0 35)))))
|
||||
|
||||
(defun paint (mouse painter)
|
||||
(|setBrush| painter (mouse-brush mouse))
|
||||
(|drawEllipse| painter '(-10 -20 20 40))
|
||||
;; eyes
|
||||
(|setBrush| painter *brush-eyes*)
|
||||
(|drawEllipse| painter '(-10 -17 8 8))
|
||||
(|drawEllipse| painter '(2 -17 8 8))
|
||||
;; nose
|
||||
(|setBrush| painter *brush-nose*)
|
||||
(|drawEllipse| painter '(-2 -22 4 4))
|
||||
;; pupils
|
||||
(let ((dir (mouse-eye-direction mouse)))
|
||||
(|drawEllipse| painter (list (- dir 8) -17 4 4))
|
||||
(|drawEllipse| painter (list (+ dir 4) -17 4 4)))
|
||||
;; ears
|
||||
(|setBrush| painter (if (null (|collidingItems| (|scene| mouse) mouse))
|
||||
*brush-ears*
|
||||
*brush-colliding*))
|
||||
(|drawEllipse| painter '(-17 -12 16 16))
|
||||
(|drawEllipse| painter '(1 -12 16 16))
|
||||
;; tail
|
||||
(|setBrush| painter *brush-tail*)
|
||||
(|drawPath| painter *painter-path-tail*))
|
||||
|
||||
(defun advance (mouse step)
|
||||
(unless (zerop step)
|
||||
(labels ((normalize-angle (a)
|
||||
(x:while (minusp a)
|
||||
(incf a +2pi+))
|
||||
(x:while (> a +2pi+)
|
||||
(decf a +2pi+))
|
||||
a)
|
||||
(dx (line)
|
||||
(- (third line) (first line)))
|
||||
(dy (line)
|
||||
(- (fourth line) (second line)))
|
||||
(len (line)
|
||||
(let ((x (dx line))
|
||||
(y (dy line)))
|
||||
(sqrt (+ (* x x) (* y y)))))
|
||||
(map-from (p)
|
||||
(|mapFromScene| mouse p))
|
||||
(map-to (p)
|
||||
(|mapToScene| mouse p)))
|
||||
(let ((line-to-center (append '(0 0) (map-from '(0 0)))))
|
||||
(if (> (len line-to-center) 150)
|
||||
(let ((angle-to-center (acos (/ (dx line-to-center) (len line-to-center)))))
|
||||
(when (minusp (dy line-to-center))
|
||||
(setf angle-to-center (- +2pi+ angle-to-center)))
|
||||
(setf angle-to-center (normalize-angle (+ (- pi angle-to-center)
|
||||
(/ pi 2))))
|
||||
(cond ((< (/ pi 4) angle-to-center pi)
|
||||
;; rotate left
|
||||
(incf (mouse-angle mouse)
|
||||
(if (< (mouse-angle mouse) (/ (- pi) 2)) 0.25 -0.25)))
|
||||
((and (>= angle-to-center pi)
|
||||
(< angle-to-center (+ pi (/ pi 2) (/ pi 4))))
|
||||
;; rotate right
|
||||
(incf (mouse-angle mouse)
|
||||
(if (< (mouse-angle mouse) (/ pi 2)) 0.25 -0.25)))))
|
||||
(let ((sin (sin (mouse-angle mouse))))
|
||||
(incf (mouse-angle mouse) (cond ((minusp sin) 0.25)
|
||||
((plusp sin) -0.25)
|
||||
(t 0))))))
|
||||
;; try not to crash with any other mice
|
||||
(let ((danger-mice (|items| (|scene| mouse)
|
||||
(append (map-to '(0 0))
|
||||
(map-to '(-30 -50))
|
||||
(map-to '(30 -50)))
|
||||
|Qt.IntersectsItemShape|
|
||||
|Qt.AscendingOrder|)))
|
||||
(dolist (danger-mouse danger-mice)
|
||||
(unless (qeql mouse danger-mouse)
|
||||
(let* ((line-to-mouse (append '(0 0)
|
||||
(|mapFromItem| mouse danger-mouse '(0 0))))
|
||||
(angle-to-mouse (acos (/ (dx line-to-mouse) (len line-to-mouse)))))
|
||||
(when (minusp (dy line-to-mouse))
|
||||
(setf angle-to-mouse (- +2pi+ angle-to-mouse)))
|
||||
(setf angle-to-mouse (normalize-angle (+ (- pi angle-to-mouse)
|
||||
(/ pi 2))))
|
||||
(cond ((and (>= angle-to-mouse 0)
|
||||
(< angle-to-mouse (/ pi 2)))
|
||||
;; rotate right
|
||||
(incf (mouse-angle mouse) 0.5))
|
||||
((and (<= angle-to-mouse +2pi+)
|
||||
(> angle-to-mouse (- +2pi+ (/ pi 2))))
|
||||
;; rotate left
|
||||
(decf (mouse-angle mouse) 0.5))))))
|
||||
;; add some random movement
|
||||
(when (and (> (length danger-mice) 1)
|
||||
(zerop (random 10)))
|
||||
(let ((rnd (/ (random 100) 500))
|
||||
(angle (mouse-angle mouse)))
|
||||
(setf (mouse-angle mouse)
|
||||
(if (zerop (random 2)) (+ angle rnd) (- angle rnd)))))
|
||||
(incf (mouse-speed mouse) (/ (- (random 100) 50) 100))
|
||||
(let ((dx (* 10 (sin (mouse-angle mouse)))))
|
||||
(setf (mouse-eye-direction mouse)
|
||||
(if (< (abs (/ dx 5)) 1) 0 (/ dx 5)))
|
||||
(|setRotation| mouse (+ dx (|rotation| mouse)))
|
||||
(|setPos| mouse (|mapToParent| mouse (list 0 (- (+ 3 (* 3 (sin (mouse-speed mouse)))))))))))))
|
||||
|
||||
(defun start ()
|
||||
(setf *random-state* (make-random-state t))
|
||||
(let ((view (qnew "QGraphicsView"
|
||||
"windowTitle" "Colliding Mice"
|
||||
"size" '(400 300))))
|
||||
(|setItemIndexMethod| *graphics-scene* |QGraphicsScene.NoIndex|)
|
||||
(x:do-with view
|
||||
(|setScene| *graphics-scene*)
|
||||
(|setRenderHint| |QPainter.Antialiasing|)
|
||||
(|setBackgroundBrush| (qnew "QBrush(QPixmap)"
|
||||
(qnew "QPixmap(QString)"
|
||||
(in-home "examples/data/icons/cheese.jpg"))))
|
||||
(|setCacheMode| |QGraphicsView.CacheBackground|)
|
||||
(|setViewportUpdateMode| |QGraphicsView.BoundingRectViewportUpdate|)
|
||||
(|setDragMode| |QGraphicsView.ScrollHandDrag|))
|
||||
(let ((count 7))
|
||||
(dotimes (i count)
|
||||
(flet ((pos (fun)
|
||||
(truncate (* 200 (funcall fun (/ (* i +2pi+) count))))))
|
||||
(let ((item (new-mouse)))
|
||||
(|setPos| item (list (pos 'sin) (pos 'cos)))
|
||||
(|addItem| *graphics-scene* item)))))
|
||||
(qconnect *timer* "timeout()" *graphics-scene* "advance()")
|
||||
(|start| *timer* 30)
|
||||
(x:do-with view |show| |raise|)))
|
||||
|
||||
;;; for playing around interactively
|
||||
|
||||
(defun m+ (&optional (n 1))
|
||||
"Add n mice."
|
||||
(dotimes (i n)
|
||||
(let ((item (new-mouse)))
|
||||
(|setPos| item (list (- 100 (random 200)) (- 100 (random 200))))
|
||||
(|addItem| *graphics-scene* item)))
|
||||
*mouse-count*)
|
||||
|
||||
(defun m- (&optional (n 1))
|
||||
"Remove n mice."
|
||||
(dotimes (i n)
|
||||
(when (zerop *mouse-count*)
|
||||
(return))
|
||||
(decf *mouse-count*)
|
||||
(qdel (first (last (|items| *graphics-scene*)))))
|
||||
*mouse-count*)
|
||||
|
||||
(defun iv (&optional (ms 30))
|
||||
"Change move interval."
|
||||
(|setInterval| *timer* ms))
|
||||
|
||||
(defun ? ()
|
||||
;; demo of QSLEEP (a SLEEP processing Qt events)
|
||||
(let ((max (print (length (|items| *graphics-scene*)))))
|
||||
(dotimes (n max)
|
||||
(print (m-))
|
||||
(qsleep 1))
|
||||
(dotimes (n max)
|
||||
(print (m+))
|
||||
(qsleep 1))))
|
||||
|
||||
#|
|
||||
(require :profile)
|
||||
|
||||
(progn
|
||||
(use-package :profile)
|
||||
(profile:profile
|
||||
paint
|
||||
advance))
|
||||
|#
|
||||
|
||||
(progn
|
||||
(start)
|
||||
(qlater (lambda () (in-package :mice))))
|
||||
|
||||
48
examples/6-download.lisp
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#-qt-wrapper-functions ; see README-OPTIONAL.txt
|
||||
(load (in-home "src/lisp/all-wrappers"))
|
||||
|
||||
(unless (eql:qrequire :network)
|
||||
(error "EQL module :network could not be found/loaded")
|
||||
(eql:qq))
|
||||
|
||||
(defpackage :download
|
||||
(:use :common-lisp :eql)
|
||||
(:export
|
||||
#:ini
|
||||
#:download))
|
||||
|
||||
(in-package :download)
|
||||
|
||||
(defvar *manager* (qnew "QNetworkAccessManager"))
|
||||
(defvar *ini* t)
|
||||
|
||||
(defun download (name)
|
||||
(when *ini*
|
||||
(setf *ini* nil)
|
||||
(qconnect *manager* "finished(QNetworkReply*)" 'download-finished))
|
||||
(qlet ((url "QUrl(QString)" name)
|
||||
(request "QNetworkRequest(QUrl)" url))
|
||||
(|get| *manager* request)))
|
||||
|
||||
(defun download-finished (reply)
|
||||
(|deleteLater| reply) ; QNetworkReply*: heap result, delete manually
|
||||
(let ((error (|error| reply)))
|
||||
(if (= |QNetworkReply.NoError| error)
|
||||
(let ((data (|readAll| reply)))
|
||||
(save-data data)
|
||||
(|information.QMessageBox| nil "EQL"
|
||||
(format nil (tr "Downloaded ~:D bytes, see \"download.data\".") (length data))))
|
||||
(show-error error))))
|
||||
|
||||
(defun save-data (data)
|
||||
(with-open-file (s "download.data" :direction :output :if-exists :supersede
|
||||
:element-type '(signed-byte 8))
|
||||
(write-sequence data s)))
|
||||
|
||||
(defun show-error (error)
|
||||
(let ((msg (x:when-it (find error (cdadr (qenums "QNetworkReply" "NetworkError")) :key 'cdr)
|
||||
(format nil (tr "Download error: <span style='color:red; font-weight:bold;'>~A</span>")
|
||||
(car x:it)))))
|
||||
(|critical.QMessageBox| nil "EQL" (or msg (tr "Unknown download error.")))))
|
||||
|
||||
(download "http://planet.lisp.org/")
|
||||
6
examples/7-Sokoban/3rd-party/CONTRIBUTORS
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# Please add yourself to this file when you submit a patch.
|
||||
|
||||
Julian Fondren <ayrnieu@gmail.com>
|
||||
- Maintainer.
|
||||
- Contributed simple-ui ! :D
|
||||
- also: raw-ui , cl-sokoban.el
|
||||
3
examples/7-Sokoban/3rd-party/COPYING
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
BSD with no advertisement clause.
|
||||
|
||||
Copyrights held by their respective authors.
|
||||
1
examples/7-Sokoban/3rd-party/README.txt
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
Please see http://www.cliki.net/CL-Sokoban for the original game.
|
||||
816
examples/7-Sokoban/3rd-party/levels.lisp
vendored
Normal file
|
|
@ -0,0 +1,816 @@
|
|||
(in-package :cl-sokoban)
|
||||
|
||||
(defmaze
|
||||
" ##### "
|
||||
" # # "
|
||||
" #$ # "
|
||||
" ### $## "
|
||||
" # $ $ # "
|
||||
"### # ## # ######"
|
||||
"# # ## ##### ..#"
|
||||
"# $ $ ..#"
|
||||
"##### ### #@## ..#"
|
||||
" # #########"
|
||||
" ####### ")
|
||||
|
||||
(defmaze
|
||||
"############ "
|
||||
"#.. # ###"
|
||||
"#.. # $ $ #"
|
||||
"#.. #$#### #"
|
||||
"#.. @ ## #"
|
||||
"#.. # # $ ##"
|
||||
"###### ##$ $ #"
|
||||
" # $ $ $ $ #"
|
||||
" # # #"
|
||||
" ############")
|
||||
|
||||
(defmaze
|
||||
" ######## "
|
||||
" # @# "
|
||||
" # $#$ ## "
|
||||
" # $ $# "
|
||||
" ##$ $ # "
|
||||
"######### $ # ###"
|
||||
"#.... ## $ $ #"
|
||||
"##... $ $ #"
|
||||
"#.... ##########"
|
||||
"######## ")
|
||||
|
||||
(defmaze
|
||||
" ########"
|
||||
" # ....#"
|
||||
"############ ....#"
|
||||
"# # $ $ ....#"
|
||||
"# $$$#$ $ # ....#"
|
||||
"# $ $ # ....#"
|
||||
"# $$ #$ $ $########"
|
||||
"# $ # # "
|
||||
"## ######### "
|
||||
"# # ## "
|
||||
"# $ ## "
|
||||
"# $$#$$ @# "
|
||||
"# # ## "
|
||||
"########### ")
|
||||
|
||||
(defmaze
|
||||
" ##### "
|
||||
" # #####"
|
||||
" # #$## #"
|
||||
" # $ #"
|
||||
"######### ### #"
|
||||
"#.... ## $ $###"
|
||||
"#.... $ $$ ## "
|
||||
"#.... ##$ $ @# "
|
||||
"######### $ ## "
|
||||
" # $ $ # "
|
||||
" ### ## # "
|
||||
" # # "
|
||||
" ###### ")
|
||||
|
||||
(defmaze
|
||||
"###### ### "
|
||||
"#.. # ##@##"
|
||||
"#.. ### #"
|
||||
"#.. $$ #"
|
||||
"#.. # # $ #"
|
||||
"#..### # $ #"
|
||||
"#### $ #$ #"
|
||||
" # $# $ #"
|
||||
" # $ $ #"
|
||||
" # ## #"
|
||||
" #########")
|
||||
|
||||
(defmaze
|
||||
" ##### "
|
||||
" ####### ##"
|
||||
"## # @## $$ #"
|
||||
"# $ #"
|
||||
"# $ ### #"
|
||||
"### #####$###"
|
||||
"# $ ### ..# "
|
||||
"# $ $ $ ...# "
|
||||
"# ###...# "
|
||||
"# $$ # #...# "
|
||||
"# ### ##### "
|
||||
"#### ")
|
||||
|
||||
(defmaze
|
||||
" #### "
|
||||
" # ###########"
|
||||
" # $ $ $ #"
|
||||
" # $# $ # $ #"
|
||||
" # $ $ # #"
|
||||
"### $# # #### #"
|
||||
"#@#$ $ $ ## #"
|
||||
"# $ #$# # #"
|
||||
"# $ $ $ $ #"
|
||||
"##### #########"
|
||||
" # # "
|
||||
" # # "
|
||||
" #......# "
|
||||
" #......# "
|
||||
" #......# "
|
||||
" ######## ")
|
||||
|
||||
(defmaze
|
||||
" #######"
|
||||
" # ...#"
|
||||
" ##### ...#"
|
||||
" # . .#"
|
||||
" # ## ...#"
|
||||
" ## ## ...#"
|
||||
" ### ########"
|
||||
" # $$$ ## "
|
||||
" ##### $ $ #####"
|
||||
"## #$ $ # #"
|
||||
"#@ $ $ $ $ #"
|
||||
"###### $$ $ #####"
|
||||
" # # "
|
||||
" ######## ")
|
||||
|
||||
(defmaze
|
||||
" ### #############"
|
||||
"##@#### # #"
|
||||
"# $$ $$ $ $ ...#"
|
||||
"# $$$# $ #...#"
|
||||
"# $ # $$ $$ #...#"
|
||||
"### # $ #...#"
|
||||
"# # $ $ $ #...#"
|
||||
"# ###### ###...#"
|
||||
"## # # $ $ #...#"
|
||||
"# ## # $$ $ $##..#"
|
||||
"# ..# # $ #.#"
|
||||
"# ..# # $$$ $$$ #.#"
|
||||
"##### # # #.#"
|
||||
" # ######### #.#"
|
||||
" # #.#"
|
||||
" ###############")
|
||||
|
||||
(defmaze
|
||||
" #### "
|
||||
" #### # # "
|
||||
" ### @###$ # "
|
||||
" ## $ # "
|
||||
" ## $ $$## ## "
|
||||
" # #$## # "
|
||||
" # # $ $$ # ### "
|
||||
" # $ # # $ #####"
|
||||
"#### # $$ # #"
|
||||
"#### ## $ #"
|
||||
"#. ### ########"
|
||||
"#.. ..# #### "
|
||||
"#...#.# "
|
||||
"#.....# "
|
||||
"####### ")
|
||||
|
||||
(defmaze
|
||||
"################ "
|
||||
"# # "
|
||||
"# # ###### # "
|
||||
"# # $ $ $ $# # "
|
||||
"# # $@$ ## ##"
|
||||
"# # $ $ $###...#"
|
||||
"# # $ $ ##...#"
|
||||
"# ###$$$ $ ##...#"
|
||||
"# # ## ##...#"
|
||||
"##### ## ##...#"
|
||||
" ##### ###"
|
||||
" # # "
|
||||
" ####### ")
|
||||
|
||||
(defmaze
|
||||
" ######### "
|
||||
" ## ## ###### "
|
||||
"### # # ###"
|
||||
"# $ #$ # # ... #"
|
||||
"# # $#@$## # #.#. #"
|
||||
"# # #$ # . . #"
|
||||
"# $ $ # # #.#. #"
|
||||
"# ## ##$ $ . . #"
|
||||
"# $ # # #$#.#. #"
|
||||
"## $ $ $ $... #"
|
||||
" #$ ###### ## #"
|
||||
" # # ##########"
|
||||
" #### ")
|
||||
|
||||
(defmaze
|
||||
" ####### "
|
||||
" ####### # "
|
||||
" # # $@$ # "
|
||||
" #$$ # #########"
|
||||
" # ###......## #"
|
||||
" # $......## # #"
|
||||
" # ###...... #"
|
||||
"## #### ### #$##"
|
||||
"# #$ # $ # # "
|
||||
"# $ $$$ # $## # "
|
||||
"# $ $ ###$$ # # "
|
||||
"##### $ # # "
|
||||
" ### ### # # "
|
||||
" # # # "
|
||||
" ######## # "
|
||||
" #### ")
|
||||
|
||||
(defmaze
|
||||
" ######## "
|
||||
" # # # "
|
||||
" # $ # "
|
||||
" ### #$ #### "
|
||||
" # $ ##$ # "
|
||||
" # # @ $ # $# "
|
||||
" # # $ ####"
|
||||
" ## ####$## #"
|
||||
" # $#.....# # #"
|
||||
" # $..*$. $# ###"
|
||||
"## #.....# # "
|
||||
"# ### ####### "
|
||||
"# $$ # # "
|
||||
"# # # "
|
||||
"###### # "
|
||||
" ##### ")
|
||||
|
||||
(defmaze
|
||||
"##### "
|
||||
"# ## "
|
||||
"# # #### "
|
||||
"# $ #### # "
|
||||
"# $$ $ $# "
|
||||
"###@ #$ ## "
|
||||
" # ## $ $ ##"
|
||||
" # $ ## ## .#"
|
||||
" # #$##$ #.#"
|
||||
" ### $..##.#"
|
||||
" # #.*...#"
|
||||
" # $$ #.....#"
|
||||
" # #########"
|
||||
" # # "
|
||||
" #### ")
|
||||
|
||||
(defmaze
|
||||
" ########## "
|
||||
" #.. # # "
|
||||
" #.. # "
|
||||
" #.. # #### "
|
||||
" ####### # ##"
|
||||
" # #"
|
||||
" # # ## # #"
|
||||
"#### ## #### ##"
|
||||
"# $ ##### # #"
|
||||
"# # $ $ # $ #"
|
||||
"# @$ $ # ##"
|
||||
"#### ## ####### "
|
||||
" # # "
|
||||
" ###### ")
|
||||
|
||||
(defmaze
|
||||
" ########### "
|
||||
" # . # # "
|
||||
" # #. @ # "
|
||||
" ##### ##..# #### "
|
||||
"## # ..### ###"
|
||||
"# $ #... $ # $ #"
|
||||
"# .. ## ## ## #"
|
||||
"####$##$# $ # # #"
|
||||
" ## # #$ $$ # #"
|
||||
" # $ # # # $## #"
|
||||
" # #"
|
||||
" # ########### #"
|
||||
" #### ####")
|
||||
|
||||
(defmaze
|
||||
" ###### "
|
||||
" # @#### "
|
||||
"##### $ # "
|
||||
"# ## #### "
|
||||
"# $ # ## # "
|
||||
"# $ # ##### # "
|
||||
"## $ $ # # "
|
||||
"## $ $ ### # # "
|
||||
"## # $ # # # "
|
||||
"## # #$# # # "
|
||||
"## ### # # ######"
|
||||
"# $ #### # #....#"
|
||||
"# $ $ ..#.#"
|
||||
"####$ $# $ ....#"
|
||||
"# # ## ....#"
|
||||
"###################")
|
||||
|
||||
(defmaze
|
||||
" ########## "
|
||||
"##### #### "
|
||||
"# # $ #@ # "
|
||||
"# #######$#### ###"
|
||||
"# # ## # #$ ..#"
|
||||
"# # $ # # #.#"
|
||||
"# # $ # #$ ..#"
|
||||
"# # ### ## #.#"
|
||||
"# ### # # #$ ..#"
|
||||
"# # # #### #.#"
|
||||
"# #$ $ $ #$ ..#"
|
||||
"# $ # $ $ # #.#"
|
||||
"#### $### #$ ..#"
|
||||
" # $$ ###....#"
|
||||
" # ## ######"
|
||||
" ######## ")
|
||||
|
||||
(defmaze
|
||||
"######### "
|
||||
"# # "
|
||||
"# #### "
|
||||
"## #### # # "
|
||||
"## #@## # "
|
||||
"# $$$ $ $$# "
|
||||
"# # ## $ # "
|
||||
"# # ## $ ####"
|
||||
"#### $$$ $# #"
|
||||
" # ## ....#"
|
||||
" # # # #.. .#"
|
||||
" # # # ##...#"
|
||||
" ##### $ #...#"
|
||||
" ## #####"
|
||||
" ##### ")
|
||||
|
||||
(defmaze
|
||||
"###### #### "
|
||||
"# ####### #####"
|
||||
"# $# # $ # #"
|
||||
"# $ $ $ # $ $ #"
|
||||
"##$ $ # @# $ #"
|
||||
"# $ ########### ##"
|
||||
"# # #.......# $# "
|
||||
"# ## # ......# # "
|
||||
"# # $........$ # "
|
||||
"# # $ #.... ..# # "
|
||||
"# $ $####$#### $# "
|
||||
"# $ ### $ $ ##"
|
||||
"# $ $ $ $ #"
|
||||
"## ###### $ ##### #"
|
||||
"# # #"
|
||||
"###################")
|
||||
|
||||
(defmaze
|
||||
" ####### "
|
||||
" # # #### "
|
||||
"##### $#$ # ## "
|
||||
"#.. # # # # "
|
||||
"#.. # $#$ # $#### "
|
||||
"#. # #$ # # "
|
||||
"#.. $# # $ # "
|
||||
"#..@# #$ #$ # # "
|
||||
"#.. # $# $# # "
|
||||
"#.. # #$$#$ # ##"
|
||||
"#.. # $# # $#$ #"
|
||||
"#.. # # # # #"
|
||||
"##. #### ##### #"
|
||||
" #### #### #####")
|
||||
|
||||
(defmaze
|
||||
"############### "
|
||||
"#.......... .#### "
|
||||
"#..........$$.# # "
|
||||
"###########$ # ##"
|
||||
"# $ $ $ #"
|
||||
"## #### # $ # #"
|
||||
"# # ## # ##"
|
||||
"# $# # ## ### ##"
|
||||
"# $ #$### ### ##"
|
||||
"### $ # # ### ##"
|
||||
"### $ ## # # ##"
|
||||
" # $ # $ $ $ #"
|
||||
" # $ $#$$$ # #"
|
||||
" # # $ #####"
|
||||
" # @## # # # "
|
||||
" ############## ")
|
||||
|
||||
(defmaze
|
||||
"#### "
|
||||
"# ############## "
|
||||
"# # ..#......# "
|
||||
"# # # ##### ...# "
|
||||
"##$# ........# "
|
||||
"# ##$###### ####"
|
||||
"# $ # ######@ #"
|
||||
"##$ # $ ###### #"
|
||||
"# $ #$$$## #"
|
||||
"# # #$#$###"
|
||||
"# #### #$$$$$ # "
|
||||
"# # $ # # "
|
||||
"# # ## ###"
|
||||
"# ######$###### $ #"
|
||||
"# # # #"
|
||||
"########## #####")
|
||||
|
||||
(defmaze
|
||||
" ####### "
|
||||
" # # ##### "
|
||||
"## # #...### "
|
||||
"# $# #... # "
|
||||
"# $ #$$ ... # "
|
||||
"# $# #... .# "
|
||||
"# # $########"
|
||||
"##$ $ $ #"
|
||||
"## # $$ # #"
|
||||
" ###### ##$$@#"
|
||||
" # ##"
|
||||
" ######## ")
|
||||
|
||||
(defmaze
|
||||
" ################# "
|
||||
" #... # # ##"
|
||||
"##..... $## # #$ #"
|
||||
"#......# $ # #"
|
||||
"#......# # # # #"
|
||||
"######### $ $ $ #"
|
||||
" # #$##$ ##$##"
|
||||
" ## $ # $ #"
|
||||
" # ## ### # ##$ #"
|
||||
" # $ $$ $ $ #"
|
||||
" # $ $##$ ######"
|
||||
" ####### @ ## "
|
||||
" ###### ")
|
||||
|
||||
(defmaze
|
||||
" ##### "
|
||||
" ##### # "
|
||||
" ## $ $ ####"
|
||||
"##### $ $ $ ##.#"
|
||||
"# $$ ##..#"
|
||||
"# ###### ###.. #"
|
||||
"## # # #... #"
|
||||
"# $ # #... #"
|
||||
"#@ #$ ## ####...#"
|
||||
"#### $ $$ ##..#"
|
||||
" ## $ $ $...#"
|
||||
" # $$ $ # .#"
|
||||
" # $ $ ####"
|
||||
" ###### # "
|
||||
" ##### ")
|
||||
|
||||
(defmaze
|
||||
"##### "
|
||||
"# ## "
|
||||
"# $ ######### "
|
||||
"## # # ######"
|
||||
"## # $#$#@ # #"
|
||||
"# # $ # $ #"
|
||||
"# ### ######### ##"
|
||||
"# ## ..*..... # ##"
|
||||
"## ## *.$..$.$ # ##"
|
||||
"# $########## ##$ #"
|
||||
"# $ $ $ $ #"
|
||||
"# # # # # #"
|
||||
"###################")
|
||||
|
||||
(defmaze
|
||||
" ########### "
|
||||
" # # # "
|
||||
"##### # $ $ # "
|
||||
"# ##### $## # ## "
|
||||
"# $ ## # ## $ # "
|
||||
"# $ @$$ # ##$$$ # "
|
||||
"## ### # ## # "
|
||||
"## # ### #####$# "
|
||||
"## # $ #....# "
|
||||
"# ### ## $ #....##"
|
||||
"# $ $ # #..$. #"
|
||||
"# ## $ # ##.... #"
|
||||
"##### ######...##"
|
||||
" ##### ##### ")
|
||||
|
||||
(defmaze
|
||||
" #### "
|
||||
" # ######### "
|
||||
" ## ## # # "
|
||||
" # $# $@$ #### "
|
||||
" #$ $ # $ $# ##"
|
||||
"## $## #$ $ #"
|
||||
"# # # # $$$ #"
|
||||
"# $ $ $## ####"
|
||||
"# $ $ #$# # # "
|
||||
"## ### ###$ # "
|
||||
" # #.... # "
|
||||
" ####......#### "
|
||||
" #....#### "
|
||||
" #...## "
|
||||
" #...# "
|
||||
" ##### ")
|
||||
|
||||
(defmaze
|
||||
" #### "
|
||||
" ##### # "
|
||||
" ## $# "
|
||||
"## $ ## ### "
|
||||
"#@$ $ # $ # "
|
||||
"#### ## $# "
|
||||
" #....#$ $ # "
|
||||
" #....# $# "
|
||||
" #.... $$ ##"
|
||||
" #... # $ #"
|
||||
" ######$ $ #"
|
||||
" # ###"
|
||||
" #$ ### "
|
||||
" # # "
|
||||
" #### ")
|
||||
|
||||
(defmaze
|
||||
"############"
|
||||
"## ## #"
|
||||
"## $ $ #"
|
||||
"#### ## $$ #"
|
||||
"# $ # #"
|
||||
"# $$$ # ####"
|
||||
"# # # $ ##"
|
||||
"# # # $ #"
|
||||
"# $# $# #"
|
||||
"# ..# ####"
|
||||
"####.. $ #@#"
|
||||
"#.....# $# #"
|
||||
"##....# $ #"
|
||||
"###..## #"
|
||||
"############")
|
||||
|
||||
(defmaze
|
||||
" ######### "
|
||||
" #.... ## "
|
||||
" #.#.# $ ## "
|
||||
"##....# # @## "
|
||||
"# ....# # ##"
|
||||
"# #$ ##$ #"
|
||||
"## ### $ #"
|
||||
" #$ $ $ $# #"
|
||||
" # # $ $ ## #"
|
||||
" # ### ## #"
|
||||
" # ## ## ##"
|
||||
" # $ # $ # "
|
||||
" ###$ $ ### "
|
||||
" # ##### "
|
||||
" #### ")
|
||||
|
||||
(defmaze
|
||||
"############ ######"
|
||||
"# # # ###....#"
|
||||
"# $$# @ .....#"
|
||||
"# # ### # ....#"
|
||||
"## ## ### # ....#"
|
||||
" # $ $ # # ####"
|
||||
" # $ $## # #"
|
||||
"#### # #### # ## #"
|
||||
"# # #$ ## # #"
|
||||
"# $ $ # ## # ##"
|
||||
"# # $ $ # # # "
|
||||
"# $ ## ## # ##### "
|
||||
"# $$ $$ # "
|
||||
"## ## ### $ # "
|
||||
" # # # # "
|
||||
" ###### ###### ")
|
||||
|
||||
(defmaze
|
||||
" ##### "
|
||||
"##### ###### # "
|
||||
"# #### $ $ $ # "
|
||||
"# $ ## ## ## ## "
|
||||
"# $ $ $ $ # "
|
||||
"### $ ## ## ##"
|
||||
" # ##### #####$$ #"
|
||||
" ##$##### @## #"
|
||||
" # $ ###$### $ ##"
|
||||
" # $ # ### ### "
|
||||
" # $$ $ # $$ # "
|
||||
" # # ## # "
|
||||
" #######.. .### "
|
||||
" #.........# "
|
||||
" #.........# "
|
||||
" ########### ")
|
||||
|
||||
(defmaze
|
||||
"########### "
|
||||
"#...... #########"
|
||||
"#...... # ## #"
|
||||
"#..### $ $ #"
|
||||
"#... $ $ # ## #"
|
||||
"#...#$##### # #"
|
||||
"### # #$ #$ #"
|
||||
" # $$ $ $ $## #"
|
||||
" # $ #$#$ ##$ #"
|
||||
" ### ## # ## #"
|
||||
" # $ $ ## ######"
|
||||
" # $ $ # "
|
||||
" ## # # # "
|
||||
" #####@##### "
|
||||
" ### ")
|
||||
|
||||
(defmaze
|
||||
" #### "
|
||||
"####### @# "
|
||||
"# $ # "
|
||||
"# $## $# "
|
||||
"##$#...# # "
|
||||
" # $... # "
|
||||
" # #. .# ##"
|
||||
" # # #$ #"
|
||||
" #$ $ #"
|
||||
" # #######"
|
||||
" #### ")
|
||||
|
||||
(defmaze
|
||||
" ######"
|
||||
" #############....#"
|
||||
"## ## ##....#"
|
||||
"# $$## $ @##....#"
|
||||
"# $$ $# ....#"
|
||||
"# $ ## $$ # # ...#"
|
||||
"# $ ## $ # ....#"
|
||||
"## ##### ### ##.###"
|
||||
"## $ $ ## . #"
|
||||
"# $### # ##### ###"
|
||||
"# $ # # "
|
||||
"# $ #$ $ $### # "
|
||||
"# $$$# $ # #### "
|
||||
"# # $$ # "
|
||||
"###### ### "
|
||||
" ##### ")
|
||||
|
||||
(defmaze
|
||||
" ############ "
|
||||
" # ##"
|
||||
" # # #$$ $ #"
|
||||
" #$ #$# ## @#"
|
||||
" ## ## # $ # ##"
|
||||
" # $ #$ # # "
|
||||
" # # $ # # "
|
||||
" ## $ $ ## # "
|
||||
" # # ## $ # "
|
||||
" # ## $$# # "
|
||||
"######$$ # # "
|
||||
"#....# ######## "
|
||||
"#.#... ## "
|
||||
"#.... # "
|
||||
"#.... # "
|
||||
"######### ")
|
||||
|
||||
(defmaze
|
||||
" ##### "
|
||||
" ## ## "
|
||||
" ## # "
|
||||
" ## $$ # "
|
||||
" ## $$ $ # "
|
||||
" # $ $ # "
|
||||
"#### # $$ #####"
|
||||
"# ######## ## #"
|
||||
"#. $$$@#"
|
||||
"#.# ####### ## ##"
|
||||
"#.# #######. #$ $##"
|
||||
"#........... # #"
|
||||
"############## $ #"
|
||||
" ## ##"
|
||||
" #### ")
|
||||
|
||||
(defmaze
|
||||
" ######## "
|
||||
" #### ######"
|
||||
" # ## $ $ @#"
|
||||
" # ## ##$#$ $ $##"
|
||||
"### ......# $$ ##"
|
||||
"# ......# # #"
|
||||
"# # ......#$ $ #"
|
||||
"# #$...... $$# $ #"
|
||||
"# ### ###$ $ ##"
|
||||
"### $ $ $ $ # "
|
||||
" # $ $ $ $ # "
|
||||
" ###### ###### "
|
||||
" ##### ")
|
||||
|
||||
(defmaze
|
||||
" ####### "
|
||||
" ##### # #### "
|
||||
" # # $ # "
|
||||
" #### #$$ ## ## # "
|
||||
"## # # ## ###"
|
||||
"# ### $#$ $ $ #"
|
||||
"#... # ## # #"
|
||||
"#...# @ # ### ##"
|
||||
"#...# ### $ $ #"
|
||||
"######## ## # #"
|
||||
" #########")
|
||||
|
||||
(defmaze
|
||||
" ##### "
|
||||
" # # "
|
||||
" # # ####### "
|
||||
" # $@###### "
|
||||
" # $ ##$ ### # "
|
||||
" # #### $ $ # "
|
||||
" # ##### # #$ ####"
|
||||
"## #### ##$ #"
|
||||
"# $# $ # ## ## #"
|
||||
"# # #...# #"
|
||||
"###### ### ... #"
|
||||
" #### # #...# #"
|
||||
" # ### # #"
|
||||
" # #"
|
||||
" #########")
|
||||
|
||||
(defmaze
|
||||
"##### #### "
|
||||
"#...# # #### "
|
||||
"#...### $ # "
|
||||
"#....## $ $### "
|
||||
"##....## $ # "
|
||||
"###... ## $ $ # "
|
||||
"# ## # $ # "
|
||||
"# ## # ### ####"
|
||||
"# $ # #$ $ #"
|
||||
"# $ @ $ $ #"
|
||||
"# # $ $$ $ ###"
|
||||
"# ###### ### "
|
||||
"# ## #### "
|
||||
"### ")
|
||||
|
||||
(defmaze
|
||||
"########## "
|
||||
"# #### "
|
||||
"# ###### # ##"
|
||||
"# # $ $ $ $ #"
|
||||
"# #$ #"
|
||||
"###$ $$# ###"
|
||||
" # ## # $## "
|
||||
" ##$# $ @# "
|
||||
" # $ $ ### "
|
||||
" # # $ # "
|
||||
" # ## # # "
|
||||
" ## ##### # "
|
||||
" # # "
|
||||
" #.......### "
|
||||
" #.......# "
|
||||
" ######### ")
|
||||
|
||||
(defmaze
|
||||
" #### "
|
||||
" ######### ## "
|
||||
"## $ $ #####"
|
||||
"# ## ## ##...#"
|
||||
"# #$$ $ $$#$##...#"
|
||||
"# # @ # ...#"
|
||||
"# $# ###$$ ...#"
|
||||
"# $ $$ $ ##....#"
|
||||
"###$ #######"
|
||||
" # ####### "
|
||||
" #### ")
|
||||
|
||||
(defmaze
|
||||
" ######### "
|
||||
" #*.$#$.$# "
|
||||
" #.*.$.$.# "
|
||||
" #*.$.$.$# "
|
||||
" #.*.$.$.# "
|
||||
" #*.$.$.$# "
|
||||
" ### ### "
|
||||
" # # "
|
||||
"###### ######"
|
||||
"# #"
|
||||
"# $ $ $ $ $ #"
|
||||
"## $ $ $ $ ##"
|
||||
" #$ $ $ $ $# "
|
||||
" # $@$ # "
|
||||
" # ##### # "
|
||||
" #### #### ")
|
||||
|
||||
(defmaze
|
||||
" #### "
|
||||
" # ## "
|
||||
" # ## "
|
||||
" # $$ ## "
|
||||
" ###$ $ ## "
|
||||
" #### $ # "
|
||||
"### # ##### # "
|
||||
"# # #....$ # "
|
||||
"# # $ ....# # "
|
||||
"# $ # #.*..# # "
|
||||
"### #### ### # "
|
||||
" #### @$ ##$##"
|
||||
" ### $ #"
|
||||
" # ## #"
|
||||
" #########")
|
||||
|
||||
(defmaze
|
||||
" ############ "
|
||||
" ##.. # # "
|
||||
" ##..* $ $ # "
|
||||
" ##..*.# # # $## "
|
||||
" #..*.# # # $ # "
|
||||
"####...# # # # "
|
||||
"# ## # # "
|
||||
"# @$ $ ### # ## "
|
||||
"# $ $ # # # "
|
||||
"###$$ # # # # # "
|
||||
" # $ # # #####"
|
||||
" # $# ##### #"
|
||||
" #$ # # # #"
|
||||
" # ### ## #"
|
||||
" # # # ##"
|
||||
" #### ###### ")
|
||||
|
||||
|
||||
|
||||
(setf *mazes* (nreverse *mazes*))
|
||||
101
examples/7-Sokoban/3rd-party/sokoban.lisp
vendored
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
(defpackage :cl-sokoban
|
||||
(:nicknames :sokoban)
|
||||
(:use :cl)
|
||||
(:export #:*mazes*
|
||||
#:*rules*
|
||||
#:maze #:maze-player #:maze-dimensions #:maze-text
|
||||
#:copy-maze
|
||||
#:simple-ui
|
||||
#:move
|
||||
#:defmaze))
|
||||
|
||||
(in-package :cl-sokoban)
|
||||
|
||||
(defvar *mazes* nil
|
||||
"A list of two-dimensional character arrays, describing Sokoban puzzles.")
|
||||
|
||||
(defvar *rules*
|
||||
'(("@ " " @")
|
||||
("@." " &")
|
||||
("& " ".@")
|
||||
("&." ".&")
|
||||
("@$ " " @$")
|
||||
("@$." " @*")
|
||||
("&$ " ".@$")
|
||||
("&$." ".@*")
|
||||
("@* " " &$")
|
||||
("@*." " &*")
|
||||
("&* " ".&$")
|
||||
("&*." ".&*"))
|
||||
"A list of textual transformation rules that the cl-sokoban mover steps
|
||||
through. A rule has the format (\"from\" \" to \"); when \"from\" matches
|
||||
the maze, \" to \" replaces it in the maze.")
|
||||
|
||||
(defstruct (maze :named (:type vector) (:copier nil))
|
||||
player
|
||||
dimensions
|
||||
text)
|
||||
(defun copy-maze (maze)
|
||||
(make-maze :player (maze-player maze)
|
||||
:dimensions (maze-dimensions maze)
|
||||
:text (mapcar #'copy-seq (maze-text maze))))
|
||||
|
||||
(defun simple-ui ()
|
||||
(do ((input "" (read-line)))
|
||||
((search "q" input))
|
||||
(cond ((search "n" input) (move :north (first *mazes*)))
|
||||
((search "e" input) (move :east (first *mazes*)))
|
||||
((search "w" input) (move :west (first *mazes*)))
|
||||
((search "s" input) (move :south (first *mazes*))))
|
||||
(format t "~{~&~A~%~}" (maze-text (first *mazes*)))))
|
||||
|
||||
(defun find-player (rows)
|
||||
(loop for y from 0
|
||||
for row in rows
|
||||
for x? = (or (position #\@ row)
|
||||
(position #\& row))
|
||||
when x? return (cons x? y)
|
||||
finally (error "Maze lacks a player (@): ~S" rows)))
|
||||
|
||||
(defun move (direction maze)
|
||||
(loop for (from to) in *rules*
|
||||
when (string= from (lookahead (length from) direction maze))
|
||||
do (return (setahead to direction maze))))
|
||||
|
||||
(defun move-point (location direction)
|
||||
(case direction
|
||||
(:east (cons (1+ (car location)) (cdr location)))
|
||||
(:west (cons (1- (car location)) (cdr location)))
|
||||
(:north (cons (car location) (1- (cdr location))))
|
||||
(:south (cons (car location) (1+ (cdr location))))))
|
||||
|
||||
(defun off-maze-p (location maze)
|
||||
(destructuring-bind (x . y) (maze-dimensions maze)
|
||||
(or (>= (car location) x)
|
||||
(>= (cdr location) y)
|
||||
(< (car location) 0)
|
||||
(< (cdr location) 0))))
|
||||
|
||||
(defun lookahead (distance direction maze)
|
||||
(do ((location (maze-player maze) (move-point location direction))
|
||||
(index 0 (1+ index))
|
||||
(chars nil (cons (elt (elt (maze-text maze) (cdr location))
|
||||
(car location))
|
||||
chars)))
|
||||
((or (= index distance)
|
||||
(off-maze-p location maze))
|
||||
(coerce (reverse chars) 'string))))
|
||||
|
||||
(defun setahead (string direction maze)
|
||||
(loop for char across string
|
||||
for location = (maze-player maze) then (move-point location direction)
|
||||
do (let ((row (elt (maze-text maze) (cdr location))))
|
||||
(setf (elt row (car location)) char)))
|
||||
(setf (maze-player maze) (find-player (maze-text maze))))
|
||||
|
||||
(defun defmaze (&rest rows)
|
||||
(push (make-maze :text rows
|
||||
:dimensions (cons (length (first rows))
|
||||
(length rows))
|
||||
:player (find-player rows))
|
||||
*mazes*))
|
||||
197
examples/7-Sokoban/eql-sokoban.lisp
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
;;; This is a simple GUI for CL-Sokoban, see http://www.cliki.net/CL-Sokoban
|
||||
;;;
|
||||
;;; ------------------------------------------------------------------------
|
||||
;;;
|
||||
;;; IMPORTANT NOTE
|
||||
;;;
|
||||
;;; If you use one of: QGraphicsSvgItem, QGraphicsTextItem, QGraphicsWidget
|
||||
;;; you need a "cast" in order to call QGraphicsItem methods:
|
||||
;;;
|
||||
;;; (! "setPos" ("QGraphicsItem" graphics-text-item) '(0 0)))
|
||||
;;;
|
||||
;;; (because of multiple inheritance from both QObject and QGraphicsItem)
|
||||
;;;
|
||||
;;; If you use the wrapper functions instead (see "src/lisp/all-wrappers"),
|
||||
;;; this cast is done automatically:
|
||||
;;;
|
||||
;;; (|setPos| graphics-text-item '(0 0)))
|
||||
;;;
|
||||
;;; ------------------------------------------------------------------------
|
||||
|
||||
#-qt-wrapper-functions ; see README-OPTIONAL.txt
|
||||
(load (in-home "src/lisp/all-wrappers"))
|
||||
|
||||
(load (eql:in-home "examples/7-Sokoban/3rd-party/sokoban"))
|
||||
(load (eql:in-home "examples/7-Sokoban/3rd-party/levels"))
|
||||
|
||||
(defpackage :eql-sokoban
|
||||
(:use :common-lisp :eql)
|
||||
(:export
|
||||
#:start))
|
||||
|
||||
(in-package :eql-sokoban)
|
||||
|
||||
(defconstant +item-types+ '((#\# . :wall)
|
||||
(#\$ . :object)
|
||||
(#\* . :object2)
|
||||
(#\. . :goal)
|
||||
(#\@ . :player)
|
||||
(#\& . :player2)))
|
||||
|
||||
(defparameter *items* nil)
|
||||
(defparameter *item-size* nil)
|
||||
(defparameter *maze* nil)
|
||||
(defparameter *my-mazes* (mapcar 'sokoban:copy-maze sokoban:*mazes*))
|
||||
(defparameter *scene-size* '(650 550))
|
||||
(defparameter *print-text-maze* nil "additionally print maze to terminal")
|
||||
|
||||
(defvar *scene* (qnew "QGraphicsScene"
|
||||
"sceneRect" (append '(0 0) *scene-size*)
|
||||
"backgroundBrush" (qnew "QBrush(QColor)" "#DED6AD")))
|
||||
(defvar *view* (qnew "QGraphicsView"
|
||||
"windowTitle" "Sokoban"
|
||||
"size" (mapcar (lambda (x) (+ 50 x)) *scene-size*)))
|
||||
(defvar *level* (qnew "QSlider(Qt::Orientation)" |Qt.Vertical|
|
||||
"tickInterval" 5
|
||||
"tickPosition" |QSlider.TicksRight|
|
||||
"maximum" (1- (length *my-mazes*))))
|
||||
|
||||
(defun assoc* (item alist)
|
||||
(cdr (assoc item alist)))
|
||||
|
||||
(defun char-type (char)
|
||||
(cdr (assoc char +item-types+)))
|
||||
|
||||
(defun type-char (type)
|
||||
(car (find type +item-types+ :key 'cdr)))
|
||||
|
||||
(defun ini ()
|
||||
(x:do-with *view*
|
||||
(|setScene| *scene*)
|
||||
(|setRenderHint| |QPainter.Antialiasing|)
|
||||
(|setCacheMode| |QGraphicsView.CacheBackground|)
|
||||
(|setViewportUpdateMode| |QGraphicsView.BoundingRectViewportUpdate|))
|
||||
(let ((zoom-in (qnew "QToolButton"
|
||||
"text" "Zoom In"))
|
||||
(zoom-out (qnew "QToolButton"
|
||||
"text" "Zoom Out"))
|
||||
(main (qnew "QWidget"
|
||||
"windowTitle" "Sokoban"
|
||||
"size" (|size| *view*)))
|
||||
(help (qnew "QLabel"
|
||||
"text" "<b>Arrows</b> = Move, <b>N</b> = Next, <b>P</b> = Previous, <b>R</b> = Restart"))
|
||||
(hbox1 (qnew "QHBoxLayout"))
|
||||
(hbox2 (qnew "QHBoxLayout"))
|
||||
(layout (qnew "QVBoxLayout")))
|
||||
(dolist (w (list *level* *view*))
|
||||
(|addWidget| hbox1 w))
|
||||
(dolist (w (list zoom-in zoom-out help))
|
||||
(|addWidget| hbox2 w))
|
||||
(dolist (l (list hbox1 hbox2))
|
||||
(!"addLayout" layout l))
|
||||
(|setStretchFactor| hbox2 help 1)
|
||||
(|setLayout| main layout)
|
||||
(qconnect *level* "valueChanged(int)" (lambda (val) (set-maze) (draw)))
|
||||
(qconnect zoom-in "clicked()" (lambda () (zoom :in)))
|
||||
(qconnect zoom-out "clicked()" (lambda () (zoom :out)))
|
||||
(qadd-event-filter nil |QEvent.KeyPress| 'key-pressed)
|
||||
(x:do-with main |show| |raise|)))
|
||||
|
||||
(defun set-maze ()
|
||||
(setf *maze* (nth (|value| *level*) *my-mazes*))
|
||||
(create-items)
|
||||
(draw-items :wall))
|
||||
|
||||
(defun clear-items ()
|
||||
(|clear| *scene*)
|
||||
(setf *items* (mapcar (lambda (x) (list (cdr x))) +item-types+)))
|
||||
|
||||
(defun create-items ()
|
||||
(clear-items)
|
||||
(flet ((add (types)
|
||||
(dolist (type (x:ensure-list types))
|
||||
(let ((item (create-item type)))
|
||||
(push item (cdr (assoc type *items*)))
|
||||
(|addItem| *scene* item)))))
|
||||
(dolist (row (sokoban:maze-text *maze*))
|
||||
(x:do-string (char row)
|
||||
(unless (char= #\Space char)
|
||||
(let ((type (char-type char)))
|
||||
(cond ((find type '(:player :player2))
|
||||
(add '(:player :player2)))
|
||||
((find type '(:object :object2))
|
||||
(add '(:object :object2 :goal)))
|
||||
((eql :wall type)
|
||||
(add :wall)))))))))
|
||||
|
||||
(let (pixmaps)
|
||||
(defun create-item (type)
|
||||
(let* ((char (type-char type))
|
||||
(file (in-home (format nil "examples/7-Sokoban/pics/~(~A~).png" type)))
|
||||
(pixmap (cdr (or (assoc file pixmaps :test 'string=)
|
||||
(first (push (cons file (qnew "QPixmap(QString)" file))
|
||||
pixmaps)))))
|
||||
(item (qnew "QGraphicsPixmapItem(QPixmap)" pixmap)))
|
||||
(unless *item-size*
|
||||
(setf *item-size* (cddr (|boundingRect| item))))
|
||||
item)))
|
||||
|
||||
(defun key-pressed (obj event)
|
||||
(flet ((change-level (x)
|
||||
(|setValue| *level* (+ x (|value| *level*)))))
|
||||
(case (|key| event)
|
||||
(#.|Qt.Key_Up|
|
||||
(sokoban:move :north *maze*))
|
||||
(#.|Qt.Key_Down|
|
||||
(sokoban:move :south *maze*))
|
||||
(#.|Qt.Key_Left|
|
||||
(sokoban:move :west *maze*))
|
||||
(#.|Qt.Key_Right|
|
||||
(sokoban:move :east *maze*))
|
||||
(#.|Qt.Key_N|
|
||||
(change-level 1))
|
||||
(#.|Qt.Key_P|
|
||||
(change-level -1))
|
||||
(#.|Qt.Key_R|
|
||||
(let ((level (|value| *level*)))
|
||||
(setf (nth level *my-mazes*)
|
||||
(sokoban:copy-maze (nth level sokoban:*mazes*)))
|
||||
(set-maze)))
|
||||
(t (return-from key-pressed)))
|
||||
(draw)
|
||||
t)) ; event filter
|
||||
|
||||
(defun draw-items (type)
|
||||
(let ((char (type-char type))
|
||||
(items (assoc* type *items*))
|
||||
(y 0))
|
||||
(unless (eql :wall type)
|
||||
(dolist (item items)
|
||||
(|setVisible| item nil)))
|
||||
(dolist (row (sokoban:maze-text *maze*))
|
||||
(let ((x 0))
|
||||
(x:do-string (curr-char row)
|
||||
(when (char= char curr-char)
|
||||
(let ((item (first items)))
|
||||
(|setPos| item (list x y))
|
||||
(|setVisible| item t))
|
||||
(setf items (rest items)))
|
||||
(incf x (first *item-size*))))
|
||||
(incf y (second *item-size*)))))
|
||||
|
||||
(defun draw ()
|
||||
(dolist (type '(:player :object :goal :player2 :object2))
|
||||
(draw-items type))
|
||||
(when *print-text-maze*
|
||||
(format t "~{~&~A~%~}" (sokoban:maze-text *maze*))))
|
||||
|
||||
(defun zoom (direction)
|
||||
(let ((f (if (eql :in direction) 3/2 2/3)))
|
||||
(|scale| *view* f f)))
|
||||
|
||||
(defun start ()
|
||||
(ini)
|
||||
(set-maze)
|
||||
(draw))
|
||||
|
||||
(start)
|
||||
BIN
examples/7-Sokoban/pics/goal.png
Normal file
|
After Width: | Height: | Size: 284 B |
BIN
examples/7-Sokoban/pics/object.png
Normal file
|
After Width: | Height: | Size: 469 B |
BIN
examples/7-Sokoban/pics/object2.png
Normal file
|
After Width: | Height: | Size: 478 B |
BIN
examples/7-Sokoban/pics/player.png
Normal file
|
After Width: | Height: | Size: 841 B |
BIN
examples/7-Sokoban/pics/player2.png
Normal file
|
After Width: | Height: | Size: 841 B |
BIN
examples/7-Sokoban/pics/wall.png
Normal file
|
After Width: | Height: | Size: 165 B |
3
examples/8-OpenGL/README.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
You'll need cl-opengl (see Quicklisp)
|
||||
|
||||
Run it: eql run.lisp
|
||||
201
examples/8-OpenGL/gl-widget.lisp
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
;;; This is a port of the Qt OpenGL Example "Grabber"
|
||||
|
||||
(defpackage :gl-widget
|
||||
(:use :common-lisp :eql)
|
||||
(:export
|
||||
#:*gl-widget*
|
||||
#:*timer*
|
||||
#:*x-rotation-changed*
|
||||
#:*y-rotation-changed*
|
||||
#:*z-rotation-changed*
|
||||
#:ini-gl-widget
|
||||
#:set-x-rotation
|
||||
#:set-y-rotation
|
||||
#:set-z-rotation))
|
||||
|
||||
(provide :gl-widget)
|
||||
|
||||
(in-package :gl-widget)
|
||||
|
||||
(defconstant +360+ (* 360 16))
|
||||
|
||||
(defvar *gl-widget* (qnew "QGLWidget"))
|
||||
(defvar *timer* (qnew "QTimer"))
|
||||
|
||||
(defparameter *gear1* 0)
|
||||
(defparameter *gear2* 0)
|
||||
(defparameter *gear3* 0)
|
||||
(defparameter *x-rot* 0)
|
||||
(defparameter *y-rot* 0)
|
||||
(defparameter *z-rot* 0)
|
||||
(defparameter *gear1-rot* 0)
|
||||
(defparameter *last-pos* (list 0 0))
|
||||
|
||||
(defparameter *x-rotation-changed* nil)
|
||||
(defparameter *y-rotation-changed* nil)
|
||||
(defparameter *z-rotation-changed* nil)
|
||||
|
||||
(defun ini-gl-widget ()
|
||||
(x:do-with (qoverride *gl-widget*)
|
||||
("initializeGL()" 'initialize-gl)
|
||||
("paintGL()" 'paint-gl)
|
||||
("resizeGL(int,int)" 'resize-gl)
|
||||
("mousePressEvent(QMouseEvent*)" 'mouse-press-event)
|
||||
("mouseMoveEvent(QMouseEvent*)" 'mouse-move-event))
|
||||
(qconnect *timer* "timeout()" 'advance-gears)
|
||||
(|start| *timer* 20))
|
||||
|
||||
(defmacro set-rotation (axis)
|
||||
(flet ((axis-symbol (frm)
|
||||
(intern (format nil frm axis))))
|
||||
(let ((rot (axis-symbol "*~A-ROT*"))
|
||||
(changed (axis-symbol "*~A-ROTATION-CHANGED*")))
|
||||
`(defun ,(axis-symbol "SET-~A-ROTATION") (angle)
|
||||
(setf angle (normalize-angle angle))
|
||||
(when (/= angle ,rot)
|
||||
(setf ,rot angle)
|
||||
(when ,changed
|
||||
(funcall ,changed angle))
|
||||
(|updateGL| *gl-widget*))))))
|
||||
|
||||
(set-rotation :x)
|
||||
(set-rotation :y)
|
||||
(set-rotation :z)
|
||||
|
||||
(defun initialize-gl ()
|
||||
(gl:light :light0 :position #(5 5 10 1))
|
||||
(gl:enable :lighting)
|
||||
(gl:enable :light0)
|
||||
(gl:enable :depth-test)
|
||||
(setf *gear1* (make-gear #(0.8 0.1 0.0 1.0) 1.0 4.0 1.0 0.7 20)
|
||||
*gear2* (make-gear #(0.0 0.8 0.2 1.0) 0.5 2.0 2.0 0.7 10)
|
||||
*gear3* (make-gear #(0.2 0.2 1.0 1.0) 1.3 2.0 0.5 0.7 10))
|
||||
(gl:enable :normalize)
|
||||
(gl:clear-color 0 0 0 1))
|
||||
|
||||
(defun paint-gl ()
|
||||
(gl:clear :color-buffer :depth-buffer)
|
||||
(gl:push-matrix)
|
||||
(gl:rotate (/ *x-rot* 16) 1 0 0)
|
||||
(gl:rotate (/ *y-rot* 16) 0 1 0)
|
||||
(gl:rotate (/ *z-rot* 16) 0 0 1)
|
||||
(draw-gear *gear1* -3.0 -2.0 0.0 (/ *gear1-rot* 16))
|
||||
(draw-gear *gear2* 3.1 -2.0 0.0 (- (* -2 (/ *gear1-rot* 16)) 9))
|
||||
(gl:rotate 90 1 0 0)
|
||||
(draw-gear *gear3* -3.1 -1.8 -2.2 (- (* 2 (/ *gear1-rot* 16)) 2))
|
||||
(gl:pop-matrix))
|
||||
|
||||
(defun resize-gl (width height)
|
||||
(if (|isVisible| *gl-widget*) ; needed in OSX
|
||||
(let ((side (min width height)))
|
||||
(gl:viewport (/ (- width side) 2) (/ (- height side) 2) side side)
|
||||
(gl:matrix-mode :projection)
|
||||
(gl:load-identity)
|
||||
(gl:frustum -1 1 -1 1 5 60)
|
||||
(gl:matrix-mode :modelview)
|
||||
(gl:load-identity)
|
||||
(gl:translate 0 0 -40))
|
||||
(qlater (lambda () (apply 'resize-gl (|size| *gl-widget*))))))
|
||||
|
||||
(defun mouse-press-event (event)
|
||||
(setf *last-pos* (|pos| event)))
|
||||
|
||||
(defun mouse-move-event (event)
|
||||
(let ((dx (- (|x| event) (first *last-pos*)))
|
||||
(dy (- (|y| event) (second *last-pos*)))
|
||||
(buttons (|buttons| event)))
|
||||
(flet ((button (enum)
|
||||
(plusp (logand enum buttons))))
|
||||
(cond ((button |Qt.LeftButton|)
|
||||
(set-x-rotation (+ *x-rot* (* 8 dy)))
|
||||
(set-y-rotation (+ *y-rot* (* 8 dx))))
|
||||
((button |Qt.RightButton|)
|
||||
(set-x-rotation (+ *x-rot* (* 8 dy)))
|
||||
(set-z-rotation (+ *z-rot* (* 8 dx)))))
|
||||
(setf *last-pos* (|pos| event)))))
|
||||
|
||||
(defun advance-gears ()
|
||||
(incf *gear1-rot* (* 2 16))
|
||||
(|updateGL| *gl-widget*))
|
||||
|
||||
(defun make-gear (reflectance inner-radius outer-radius thickness tooth-size tooth-count)
|
||||
(let ((list (gl:gen-lists 1))
|
||||
(r0 inner-radius)
|
||||
(r1 (- outer-radius (/ tooth-size 2)))
|
||||
(r2 (+ outer-radius (/ tooth-size 2)))
|
||||
(delta (/ (/ (* 2 pi) tooth-count) 4))
|
||||
(z (/ thickness 2)))
|
||||
(gl:new-list list :compile)
|
||||
(gl:material :front :ambient-and-diffuse reflectance)
|
||||
(gl:shade-model :flat)
|
||||
(dotimes (i 2)
|
||||
(let ((sign (if (zerop i) 1 -1)))
|
||||
(gl:normal 0 0 sign)
|
||||
(gl:begin :quad-strip)
|
||||
(dotimes (j (1+ tooth-count))
|
||||
(let ((angle (/ (* 2 pi j) tooth-count)))
|
||||
(gl:vertex (* r0 (cos angle)) (* r0 (sin angle)) (* sign z))
|
||||
(gl:vertex (* r1 (cos angle)) (* r1 (sin angle)) (* sign z))
|
||||
(gl:vertex (* r0 (cos angle)) (* r0 (sin angle)) (* sign z))
|
||||
(gl:vertex (* r1 (cos (+ angle (* 3 delta))))
|
||||
(* r1 (sin (+ angle (* 3 delta))))
|
||||
(* sign z))))
|
||||
(gl:end)
|
||||
(gl:begin :quads)
|
||||
(dotimes (j tooth-count)
|
||||
(let ((angle (/ (* 2 pi j) tooth-count)))
|
||||
(gl:vertex (* r1 (cos angle)) (* r1 (sin angle)) (* sign z))
|
||||
(gl:vertex (* r2 (cos (+ angle delta)))
|
||||
(* r2 (sin (+ angle delta)))
|
||||
(* sign z))
|
||||
(gl:vertex (* r2 (cos (+ angle (* 2 delta))))
|
||||
(* r2 (sin (+ angle (* 2 delta))))
|
||||
(* sign z))
|
||||
(gl:vertex (* r1 (cos (+ angle (* 3 delta))))
|
||||
(* r1 (sin (+ angle (* 3 delta))))
|
||||
(* sign z))))
|
||||
(gl:end)))
|
||||
(gl:begin :quad-strip)
|
||||
(dotimes (i tooth-count)
|
||||
(dotimes (j 2)
|
||||
(let ((angle (/ (* 2 pi (+ i (/ j 2)))
|
||||
tooth-count))
|
||||
(s1 r1)
|
||||
(s2 r2))
|
||||
(when (= 1 j)
|
||||
(rotatef s1 s2))
|
||||
(gl:normal (cos angle) (sin angle) 0)
|
||||
(gl:vertex (* s1 (cos angle)) (* s1 (sin angle)) z)
|
||||
(gl:vertex (* s1 (cos angle)) (* s1 (sin angle)) (- z))
|
||||
(gl:normal (- (* s2 (sin (+ angle delta))) (* s1 (sin angle)))
|
||||
(- (* s1 (cos angle)) (* s2 (cos (+ angle delta))))
|
||||
0)
|
||||
(gl:vertex (* s2 (cos (+ angle delta))) (* s2 (sin (+ angle delta))) z)
|
||||
(gl:vertex (* s2 (cos (+ angle delta))) (* s2 (sin (+ angle delta))) (- z)))))
|
||||
(gl:vertex r1 0 z)
|
||||
(gl:vertex r1 0 (- z))
|
||||
(gl:end)
|
||||
(gl:shade-model :smooth)
|
||||
(gl:begin :quad-strip)
|
||||
(dotimes (i (1+ tooth-count))
|
||||
(let ((angle (/ (* i 2 pi) tooth-count)))
|
||||
(gl:normal (- (cos angle)) (- (sin angle)) 0)
|
||||
(gl:vertex (* r0 (cos angle)) (* r0 (sin angle)) z)
|
||||
(gl:vertex (* r0 (cos angle)) (* r0 (sin angle)) (- z))))
|
||||
(gl:end)
|
||||
(gl:end-list)
|
||||
list))
|
||||
|
||||
(defun draw-gear (gear dx dy dz angle)
|
||||
(gl:push-matrix)
|
||||
(gl:translate dx dy dz)
|
||||
(gl:rotate angle 0 0 1)
|
||||
(gl:call-list gear)
|
||||
(gl:pop-matrix))
|
||||
|
||||
(defun normalize-angle (angle)
|
||||
(x:while (minusp angle)
|
||||
(incf angle +360+))
|
||||
(x:while (> angle +360+)
|
||||
(decf angle +360+))
|
||||
angle)
|
||||
136
examples/8-OpenGL/main-window.lisp
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
;;; This is a port of the Qt OpenGL Example "Grabber"
|
||||
|
||||
#-qt-wrapper-functions ; see README-OPTIONAL.txt
|
||||
(load (in-home "src/lisp/all-wrappers"))
|
||||
|
||||
(require :gl-widget (eql:in-home "examples/8-OpenGL/gl-widget"))
|
||||
|
||||
(defpackage :main-window
|
||||
(:use :common-lisp :eql :gl-widget)
|
||||
(:export
|
||||
#:start))
|
||||
|
||||
(in-package :main-window)
|
||||
|
||||
(defvar *me* (qnew "QMainWindow"))
|
||||
(defvar *pixmap-label* (qnew "QLabel"))
|
||||
(defvar *pixmap-label-area* (qnew "QScrollArea"
|
||||
"sizePolicy" (qnew "QSizePolicy(QSizePolicy::Policy,QSizePolicy::Policy)"
|
||||
|QSizePolicy.Ignored| |QSizePolicy.Ignored|)
|
||||
"minimumSize" '(50 50)))
|
||||
|
||||
(defun ini ()
|
||||
(ini-gl-widget)
|
||||
(let ((widget-area (qnew "QScrollArea"
|
||||
"widgetResizable" t
|
||||
"horizontalScrollBarPolicy" |Qt.ScrollBarAlwaysOff|
|
||||
"verticalScrollBarPolicy" |Qt.ScrollBarAlwaysOff|
|
||||
"sizePolicy" (qnew "QSizePolicy(QSizePolicy::Policy,QSizePolicy::Policy)"
|
||||
|QSizePolicy.Ignored| |QSizePolicy.Ignored|)
|
||||
"minimumSize" (list 50 50)))
|
||||
(central-widget (qnew "QWidget"))
|
||||
(central-layout (qnew "QGridLayout"))
|
||||
(x-slider (create-slider '*x-rotation-changed* 'set-x-rotation))
|
||||
(y-slider (create-slider '*y-rotation-changed* 'set-y-rotation))
|
||||
(z-slider (create-slider '*z-rotation-changed* 'set-z-rotation)))
|
||||
(|setCentralWidget| *me* central-widget)
|
||||
(|setWidget| widget-area *gl-widget*)
|
||||
(|setWidget| *pixmap-label-area* *pixmap-label*)
|
||||
(create-menus)
|
||||
(x:do-with (|addWidget| central-layout)
|
||||
(widget-area 0 0)
|
||||
(*pixmap-label-area* 0 1)
|
||||
(x-slider 1 0 1 2)
|
||||
(y-slider 2 0 1 2)
|
||||
(z-slider 3 0 1 2))
|
||||
(|setLayout| central-widget central-layout)
|
||||
(|setValue| x-slider (* 15 16))
|
||||
(|setValue| y-slider (* 345 16))
|
||||
(|setValue| z-slider 0)
|
||||
(x:do-with *me*
|
||||
(|setWindowTitle| (tr "Grabber"))
|
||||
(|resize| (list 400 300)))))
|
||||
|
||||
(defun render-into-pixmap ()
|
||||
(let ((size (get-size)))
|
||||
(when (every 'plusp size)
|
||||
(set-pixmap (|renderPixmap| *gl-widget* (first size) (second size))))))
|
||||
|
||||
(defun grab-frame-buffer ()
|
||||
(set-pixmap (|fromImage.QPixmap| (|grabFrameBuffer| *gl-widget*))))
|
||||
|
||||
(defun clear-pixmap ()
|
||||
(set-pixmap (qnew "QPixmap")))
|
||||
|
||||
(defun about ()
|
||||
(|about.QMessageBox|
|
||||
*me*
|
||||
(tr "About Grabber")
|
||||
(tr "The <b>Grabber</b> example demonstrates two approaches for rendering OpenGL into a Qt pixmap.")))
|
||||
|
||||
(defun add-action (menu text shortcut function)
|
||||
(let ((action (|addAction| menu text)))
|
||||
(when shortcut
|
||||
(|setShortcut| action (qnew "QKeySequence(QString)" shortcut)))
|
||||
(qconnect action "triggered()" function)))
|
||||
|
||||
(defun create-menus ()
|
||||
(let* ((menu-bar (|menuBar| *me*))
|
||||
(file-menu (|addMenu| menu-bar (tr "&File")))
|
||||
(help-menu (|addMenu| menu-bar (tr "&Help"))))
|
||||
;; file menu
|
||||
(add-action file-menu (tr "&Render into Pixmap...") "Ctrl+R" 'render-into-pixmap)
|
||||
(add-action file-menu (tr "&Grab Frame Buffer") "Ctrl+G" 'grab-frame-buffer)
|
||||
(add-action file-menu (tr "&Clear Pixmap") "Ctrl+L" 'clear-pixmap)
|
||||
(|addSeparator| file-menu)
|
||||
(add-action file-menu (tr "E&xit") "Ctrl+Q" (lambda () (|close| *me*)))
|
||||
;; help menu
|
||||
(add-action help-menu (tr "&About") nil 'about)
|
||||
(add-action help-menu (tr "About &Qt") nil (lambda () (|aboutQt| (qapp))))))
|
||||
|
||||
(defun create-slider (changed setter)
|
||||
(let ((slider (qnew "QSlider(Qt::Orientation)" |Qt.Horizontal|
|
||||
"minimum" 0
|
||||
"maximum" (* 360 16)
|
||||
"singleStep" (* 1 16)
|
||||
"pageStep" (* 15 16)
|
||||
"tickInterval" (* 15 16)
|
||||
"tickPosition" |QSlider.TicksRight|)))
|
||||
(qconnect slider "valueChanged(int)" setter)
|
||||
(setf (symbol-value changed) (lambda (x) (|setValue| slider x)))
|
||||
slider))
|
||||
|
||||
(defun set-pixmap (pixmap)
|
||||
(|setPixmap| *pixmap-label* pixmap)
|
||||
(let* ((size (|size| pixmap))
|
||||
(width (first size)))
|
||||
(when (equal (list (1- width) (second size))
|
||||
(|maximumViewportSize| *pixmap-label-area*))
|
||||
(setf (first size) (1- width)))
|
||||
(|resize| *pixmap-label* size)))
|
||||
|
||||
(defun get-size ()
|
||||
(let ((text (|getText.QInputDialog|
|
||||
*me*
|
||||
(tr "Grabber")
|
||||
(tr "Enter pixmap size:")
|
||||
|QLineEdit.Normal|
|
||||
(format nil "~{~D~^ x ~}" (|size| *gl-widget*))
|
||||
nil))) ; ok
|
||||
(if (qok)
|
||||
(progn
|
||||
(qlet ((reg-exp "QRegExp(QString)" "([0-9]+) *x *([0-9]+)"))
|
||||
(flet ((cap (n)
|
||||
(parse-integer (|cap| reg-exp n))))
|
||||
(when (|exactMatch| reg-exp text)
|
||||
(let ((width (cap 1))
|
||||
(height (cap 2)))
|
||||
(when (and (< 0 width 2048)
|
||||
(< 0 height 2048))
|
||||
(return-from get-size (list width height)))))))
|
||||
(|size| *gl-widget*))
|
||||
'(0 0))))
|
||||
|
||||
(defun start ()
|
||||
(ini)
|
||||
(x:do-with *me* |show| |raise|))
|
||||
11
examples/8-OpenGL/run.lisp
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#+unix (si::trap-fpe t nil)
|
||||
|
||||
(ql:quickload :cl-opengl)
|
||||
|
||||
(unless (eql:qrequire :opengl)
|
||||
(error "EQL module :opengl could not be found/loaded")
|
||||
(eql:qq))
|
||||
|
||||
(load (eql:in-home "examples/8-OpenGL/main-window"))
|
||||
|
||||
(main-window:start)
|
||||
83
examples/9-simple-lisp-editor/README.txt
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
NOTES
|
||||
=====
|
||||
|
||||
This is only an experimental, simple, "scratch buffer" like toy editor.
|
||||
|
||||
Run it:
|
||||
|
||||
0) You'll need the :network module (see QREQUIRE).
|
||||
|
||||
1) Run the independent local Lisp server:
|
||||
eql -norc local-server
|
||||
|
||||
2) Run the editor:
|
||||
eql editor <file>.lisp (defaults to "my.lisp")
|
||||
|
||||
The main motivation behind this editor is the need for a popup completer
|
||||
for the (huge) Qt library.
|
||||
|
||||
The completer works for:
|
||||
|
||||
qnew
|
||||
qlet
|
||||
qset
|
||||
qget
|
||||
qfun
|
||||
qconnect
|
||||
qoverride
|
||||
qfind-child
|
||||
|
||||
It tries to be intelligent, for example:
|
||||
|
||||
- it looks for the type (Qt class) for both global and local variables
|
||||
- it automatically cuts optional type lists in Qt function calls (qfun)
|
||||
|
||||
|
||||
|
||||
USAGE NOTES
|
||||
===========
|
||||
|
||||
There's no "New" button; instead, "new.lisp" can be used as simple template.
|
||||
|
||||
Please see the context menu of the editor window for generic editor commands
|
||||
(offered by Qt, which include some other commands too, like Ctrl+<arrow key>).
|
||||
|
||||
"Eval Region" note: (see initial status-bar message)
|
||||
Remember to change to the desired package prior to eval anything.
|
||||
|
||||
Tab completion note: hitting Tab will pop up a window with symbol completions.
|
||||
This works in both the editor and command line widget, at any cursor position.
|
||||
Currently, tab completion works for all CL and EQL symbols (including Qt
|
||||
enums).
|
||||
If the inserted symbol is a function, its argument list (if available) will be
|
||||
shown in the status bar.
|
||||
Hitting Tab after a " character will show the pathname completer instead (works
|
||||
for absolute path names only).
|
||||
|
||||
Auto indent note: hitting the Ctrl+Tab keys will auto indent the paragraph
|
||||
starting from the current line until the next empty line found.
|
||||
|
||||
On errors, the local Lisp server will pop up a debug dialog, asking for an
|
||||
ECL debug command (even for internal errors of "local-server.lisp").
|
||||
|
||||
If you want to pause/continue the local-server process, use the usual Ctrl+C
|
||||
(terminal command) and :c (ECL command).
|
||||
(N.B. might not work on Windows).
|
||||
|
||||
The "Save and Run" action (Ctrl+R) will load the current code in the local
|
||||
Lisp server process (if you don't see the application window, it might be
|
||||
in the background. Use your taskbar to show it).
|
||||
|
||||
When using "Save and Run", on errors, after the local-server entered the
|
||||
debugger, you can enter the ECL debugger command :f, which will send the
|
||||
position of the offending region to the editor, and it will be marked red.
|
||||
|
||||
Closing & re-opening the editor does not affect the local-server process.
|
||||
You may even open multiple editor instances, which will all connect to the
|
||||
same local-server.
|
||||
|
||||
You can put an ini file ".ini-eql-editor.lisp" in your working directory,
|
||||
which will be loaded on startup, having full access to all editor variables
|
||||
and functions.
|
||||
Example: (! "showMaximized" editor::*main*)
|
||||
|
||||
42
examples/9-simple-lisp-editor/data/auto-indent.lisp
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
(mapcar (lambda (x)
|
||||
(if (atom x)
|
||||
(cons (symbol-name x) 2) ; default: 2 spaces
|
||||
(cons (symbol-name (car x)) (cdr x))))
|
||||
'(case
|
||||
ccase
|
||||
ecase
|
||||
typecase
|
||||
ctypecase
|
||||
etypecase
|
||||
handler-bind
|
||||
handler-case
|
||||
catch
|
||||
defun
|
||||
defmacro
|
||||
destructuring-bind
|
||||
do
|
||||
do*
|
||||
dolist
|
||||
dotimes
|
||||
do-all-symbols
|
||||
do-symbols
|
||||
do-with
|
||||
flet
|
||||
labels
|
||||
lambda
|
||||
let
|
||||
let*
|
||||
let-it
|
||||
loop
|
||||
multiple-value-bind
|
||||
qlet
|
||||
unless
|
||||
when
|
||||
with-open-file
|
||||
with-output-to-string
|
||||
;; package :x
|
||||
do-string
|
||||
when-it
|
||||
when-it*
|
||||
while
|
||||
while-it))
|
||||
246
examples/9-simple-lisp-editor/data/editor.ui
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>main_window</class>
|
||||
<widget class="QMainWindow" name="main_window">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>605</width>
|
||||
<height>435</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<widget class="QWidget" name="layoutWidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTextEdit" name="editor"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="command"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QTextEdit" name="output"/>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="find">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>175</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>175</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Hit Return for next hit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="replace">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>175</width>
|
||||
<height>1</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>175</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Hit Return for replace</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="button_next">
|
||||
<property name="text">
|
||||
<string>Next</string>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="button_replace">
|
||||
<property name="text">
|
||||
<string>Replace</string>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="sel_label">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="select">
|
||||
<property name="text">
|
||||
<string>Select</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>605</width>
|
||||
<height>19</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
<widget class="QToolBar" name="toolBar">
|
||||
<property name="windowTitle">
|
||||
<string>toolBar</string>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<addaction name="action_open"/>
|
||||
<addaction name="action_save"/>
|
||||
<addaction name="action_save_as"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_save_and_run"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_copy"/>
|
||||
<addaction name="action_cut"/>
|
||||
<addaction name="action_insert_file"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_eval_region"/>
|
||||
<addaction name="action_repeat_eval"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_reset_lisp"/>
|
||||
</widget>
|
||||
<action name="action_open">
|
||||
<property name="text">
|
||||
<string>Open</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_save">
|
||||
<property name="text">
|
||||
<string>Save</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_save_as">
|
||||
<property name="text">
|
||||
<string>Save As</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_save_and_run">
|
||||
<property name="text">
|
||||
<string>Save and Run</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_eval_region">
|
||||
<property name="text">
|
||||
<string>Eval Region</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Eval expression enclosed in currently highlighted parenthesis</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_repeat_eval">
|
||||
<property name="text">
|
||||
<string>Repeat Eval</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Eval starting from left paren of latest eval</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_copy">
|
||||
<property name="text">
|
||||
<string>Copy ( )</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Copy highlighted region</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_cut">
|
||||
<property name="text">
|
||||
<string>Cut ( )</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Cut highlighted region</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_insert_file">
|
||||
<property name="text">
|
||||
<string>Insert File</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Insert a file at current cursor position</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_reset_lisp">
|
||||
<property name="text">
|
||||
<string>Reset Lisp</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Restart local Lisp server</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
97
examples/9-simple-lisp-editor/data/eql-keywords.lisp
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
'("define-qt-wrappers"
|
||||
"defvar-ui"
|
||||
"ensure-qt-object"
|
||||
"in-home"
|
||||
"new-qt-object"
|
||||
"qadd-event-filter"
|
||||
"qapp"
|
||||
"qapropos"
|
||||
"qapropos*"
|
||||
#+linux
|
||||
"qauto-reload-c++"
|
||||
"qcall-default"
|
||||
"qclear-event-filters"
|
||||
"qconnect"
|
||||
"qcopy"
|
||||
"qdel"
|
||||
"qdelete"
|
||||
"qdisconnect"
|
||||
"qenums"
|
||||
"qeql"
|
||||
"qescape"
|
||||
"qevents"
|
||||
"qexec"
|
||||
"qexit"
|
||||
"qfind-bound"
|
||||
"qfind-bound*"
|
||||
"qfind-child"
|
||||
"qfind-children"
|
||||
"qfrom-utf8"
|
||||
"qfun"
|
||||
"qfun*"
|
||||
"qfun+"
|
||||
"qfuns"
|
||||
"qget"
|
||||
"qgui"
|
||||
"qid"
|
||||
"qinvoke-method"
|
||||
"qinvoke-method*"
|
||||
"qinvoke-method+"
|
||||
"qinvoke-methods"
|
||||
"qlater"
|
||||
"qlet"
|
||||
"qload"
|
||||
"qload-c++"
|
||||
"qload-ui"
|
||||
"qlocal8bit"
|
||||
"qmessage-box"
|
||||
"qmsg"
|
||||
"qnew"
|
||||
"qnew-instance"
|
||||
"qnew*"
|
||||
"qnew-instance*"
|
||||
"qnull"
|
||||
"qnull-object"
|
||||
"qobject-names"
|
||||
"qok"
|
||||
"qoverride"
|
||||
"qprocess-events"
|
||||
"qproperties"
|
||||
"qproperty"
|
||||
"qq"
|
||||
"qquit"
|
||||
"qremove-event-filter"
|
||||
"qrequire"
|
||||
"qrgb"
|
||||
"qrun"
|
||||
"qrun-in-gui-thread"
|
||||
"qrun*"
|
||||
"qrun-in-gui-thread*"
|
||||
"qsel"
|
||||
"qselect"
|
||||
"qsender"
|
||||
"qset"
|
||||
"qset-color"
|
||||
"qset-ini"
|
||||
"qset-null"
|
||||
"qset-property"
|
||||
"qsignal"
|
||||
"qsingle-shot"
|
||||
"qsleep"
|
||||
"qslot"
|
||||
"qstatic-meta-object"
|
||||
"qsuper-class-name"
|
||||
"qt-object"
|
||||
"qt-object-id"
|
||||
"qt-object-name"
|
||||
"qt-object-p"
|
||||
"qt-object-pointer"
|
||||
"qt-object-unique"
|
||||
"qt-object-?"
|
||||
"qtranslate"
|
||||
"quic"
|
||||
"qui-class"
|
||||
"qui-names"
|
||||
"qutf8"
|
||||
"qversion"
|
||||
"tr")
|
||||
769
examples/9-simple-lisp-editor/data/lisp-keywords.lisp
Normal file
|
|
@ -0,0 +1,769 @@
|
|||
(let ((hash (make-hash-table :test 'equal)))
|
||||
(dolist (kw '("abort"
|
||||
"abs"
|
||||
"acons"
|
||||
"acos"
|
||||
"acosh"
|
||||
"add-method"
|
||||
"adjoin"
|
||||
"adjust-array"
|
||||
"adjustable-array-p"
|
||||
"allocate-instance"
|
||||
"alpha-char-p"
|
||||
"alphanumericp"
|
||||
"and"
|
||||
"append"
|
||||
"apply"
|
||||
"apropos"
|
||||
"apropos-list"
|
||||
"aref"
|
||||
"arithmetic-error-operands"
|
||||
"arithmetic-error-operation"
|
||||
"array-dimension"
|
||||
"array-dimensions"
|
||||
"array-displacement"
|
||||
"array-element-type"
|
||||
"array-has-fill-pointer-p"
|
||||
"array-in-bounds-p"
|
||||
"array-rank"
|
||||
"array-row-major-index"
|
||||
"array-total-size"
|
||||
"arrayp"
|
||||
"ash"
|
||||
"asin"
|
||||
"asinh"
|
||||
"assert"
|
||||
"assoc"
|
||||
"assoc-if"
|
||||
"assoc-if-not"
|
||||
"atan"
|
||||
"atanh"
|
||||
"atom"
|
||||
"bit"
|
||||
"bit-and"
|
||||
"bit-andc1"
|
||||
"bit-andc2"
|
||||
"bit-eqv"
|
||||
"bit-ior"
|
||||
"bit-nand"
|
||||
"bit-nor"
|
||||
"bit-not"
|
||||
"bit-orc1"
|
||||
"bit-orc2"
|
||||
"bit-vector-p"
|
||||
"bit-xor"
|
||||
"block"
|
||||
"boole"
|
||||
"both-case-p"
|
||||
"boundp"
|
||||
"break"
|
||||
"broadcast-stream-streams"
|
||||
"butlast"
|
||||
"byte"
|
||||
"byte-position"
|
||||
"byte-size"
|
||||
"caaaar"
|
||||
"caaadr"
|
||||
"caaar"
|
||||
"caadar"
|
||||
"caaddr"
|
||||
"caadr"
|
||||
"caar"
|
||||
"cadaar"
|
||||
"cadadr"
|
||||
"cadar"
|
||||
"caddar"
|
||||
"cadddr"
|
||||
"caddr"
|
||||
"cadr"
|
||||
"call-method"
|
||||
"call-next-method"
|
||||
"car"
|
||||
"case"
|
||||
"catch"
|
||||
"ccase"
|
||||
"cdaaar"
|
||||
"cdaadr"
|
||||
"cdaar"
|
||||
"cdadar"
|
||||
"cdaddr"
|
||||
"cdadr"
|
||||
"cdar"
|
||||
"cddaar"
|
||||
"cddadr"
|
||||
"cddar"
|
||||
"cdddar"
|
||||
"cddddr"
|
||||
"cdddr"
|
||||
"cddr"
|
||||
"cdr"
|
||||
"ceiling"
|
||||
"cell-error-name"
|
||||
"cerror"
|
||||
"change-class"
|
||||
"char"
|
||||
"char-code"
|
||||
"char-downcase"
|
||||
"char-equal"
|
||||
"char-greaterp"
|
||||
"char-int"
|
||||
"char-lessp"
|
||||
"char-name"
|
||||
"char-not-equal"
|
||||
"char-not-greaterp"
|
||||
"char-not-lessp"
|
||||
"char-upcase"
|
||||
"char/="
|
||||
"char<"
|
||||
"char<="
|
||||
"char="
|
||||
"char>"
|
||||
"char>="
|
||||
"character"
|
||||
"characterp"
|
||||
"check-type"
|
||||
"cis"
|
||||
"class-name"
|
||||
"class-of"
|
||||
"clear-input"
|
||||
"clear-output"
|
||||
"close"
|
||||
"clrhash"
|
||||
"code-char"
|
||||
"coerce"
|
||||
"compile"
|
||||
"compile-file"
|
||||
"compile-file-pathname"
|
||||
"compiled-function-p"
|
||||
"compiler-macro-function"
|
||||
"complement"
|
||||
"complex"
|
||||
"complexp"
|
||||
"compute-applicable-methods"
|
||||
"compute-restarts"
|
||||
"concatenate"
|
||||
"concatenated-stream-streams"
|
||||
"cond"
|
||||
"conjugate"
|
||||
"cons"
|
||||
"consp"
|
||||
"constantly"
|
||||
"constantp"
|
||||
"continue"
|
||||
"copy-alist"
|
||||
"copy-list"
|
||||
"copy-pprint-dispatch"
|
||||
"copy-readtable"
|
||||
"copy-seq"
|
||||
"copy-structure"
|
||||
"copy-symbol"
|
||||
"copy-tree"
|
||||
"cos"
|
||||
"cosh"
|
||||
"count"
|
||||
"count-if"
|
||||
"count-if-not"
|
||||
"ctypecase"
|
||||
"decf"
|
||||
"declaim"
|
||||
"decode-float"
|
||||
"decode-universal-time"
|
||||
"defclass"
|
||||
"defconstant"
|
||||
"defgeneric"
|
||||
"define-compiler-macro"
|
||||
"define-condition"
|
||||
"define-method-combination"
|
||||
"define-modify-macro"
|
||||
"define-setf-expander"
|
||||
"define-symbol-macro"
|
||||
"defmacro"
|
||||
"defmethod"
|
||||
"defpackage"
|
||||
"defparameter"
|
||||
"defsetf"
|
||||
"defstruct"
|
||||
"deftype"
|
||||
"defun"
|
||||
"defvar"
|
||||
"delete"
|
||||
"delete-duplicates"
|
||||
"delete-file"
|
||||
"delete-if"
|
||||
"delete-if-not"
|
||||
"delete-package"
|
||||
"denominator"
|
||||
"deposit-field"
|
||||
"describe"
|
||||
"describe-object"
|
||||
"destructuring-bind"
|
||||
"digit-char"
|
||||
"digit-char-p"
|
||||
"directory"
|
||||
"directory-namestring"
|
||||
"disassemble"
|
||||
"do"
|
||||
"do*"
|
||||
"do-all-symbols"
|
||||
"do-external-symbols"
|
||||
"do-symbols"
|
||||
"documentation"
|
||||
"dolist"
|
||||
"dotimes"
|
||||
"dribble"
|
||||
"ecase"
|
||||
"echo-stream-input-stream"
|
||||
"echo-stream-output-stream"
|
||||
"eighth"
|
||||
"elt"
|
||||
"encode-universal-time"
|
||||
"endp"
|
||||
"enough-namestring"
|
||||
"ensure-directories-exist"
|
||||
"ensure-generic-function"
|
||||
"eq"
|
||||
"eql"
|
||||
"equal"
|
||||
"equalp"
|
||||
"error"
|
||||
"etypecase"
|
||||
"eval"
|
||||
"eval-when"
|
||||
"evenp"
|
||||
"every"
|
||||
"exp"
|
||||
"export"
|
||||
"expt"
|
||||
"fboundp"
|
||||
"fceiling"
|
||||
"fdefinition"
|
||||
"ffloor"
|
||||
"fifth"
|
||||
"file-author"
|
||||
"file-error-pathname"
|
||||
"file-length"
|
||||
"file-namestring"
|
||||
"file-position"
|
||||
"file-string-length"
|
||||
"file-write-date"
|
||||
"fill"
|
||||
"fill-pointer"
|
||||
"find"
|
||||
"find-all-symbols"
|
||||
"find-class"
|
||||
"find-if"
|
||||
"find-if-not"
|
||||
"find-method"
|
||||
"find-package"
|
||||
"find-restart"
|
||||
"find-symbol"
|
||||
"finish-output"
|
||||
"first"
|
||||
"flet"
|
||||
"float"
|
||||
"float-digits"
|
||||
"float-precision"
|
||||
"float-radix"
|
||||
"float-sign"
|
||||
"floatp"
|
||||
"floor"
|
||||
"fmakunbound"
|
||||
"force-output"
|
||||
"format"
|
||||
"formatter"
|
||||
"fourth"
|
||||
"fresh-line"
|
||||
"fround"
|
||||
"ftruncate"
|
||||
"funcall"
|
||||
"function"
|
||||
"function-keywords"
|
||||
"function-lambda-expression"
|
||||
"functionp"
|
||||
"gcd"
|
||||
"gensym"
|
||||
"gentemp"
|
||||
"get"
|
||||
"get-decoded-time"
|
||||
"get-dispatch-macro-character"
|
||||
"get-internal-real-time"
|
||||
"get-internal-run-time"
|
||||
"get-macro-character"
|
||||
"get-output-stream-string"
|
||||
"get-properties"
|
||||
"get-setf-expansion"
|
||||
"get-universal-time"
|
||||
"getf"
|
||||
"gethash"
|
||||
"go"
|
||||
"graphic-char-p"
|
||||
"handler-bind"
|
||||
"handler-case"
|
||||
"hash-table-count"
|
||||
"hash-table-p"
|
||||
"hash-table-rehash-size"
|
||||
"hash-table-rehash-threshold"
|
||||
"hash-table-size"
|
||||
"hash-table-test"
|
||||
"host-namestring"
|
||||
"identity"
|
||||
"if"
|
||||
"ignore-errors"
|
||||
"imagpart"
|
||||
"import"
|
||||
"in-package"
|
||||
"incf"
|
||||
"initialize-instance"
|
||||
"input-stream-p"
|
||||
"inspect"
|
||||
"integer-decode-float"
|
||||
"integer-length"
|
||||
"integerp"
|
||||
"interactive-stream-p"
|
||||
"intern"
|
||||
"intersection"
|
||||
"invalid-method-error"
|
||||
"invoke-debugger"
|
||||
"invoke-restart"
|
||||
"invoke-restart-interactively"
|
||||
"isqrt"
|
||||
"keywordp"
|
||||
"labels"
|
||||
"lambda"
|
||||
"last"
|
||||
"lcm"
|
||||
"ldb"
|
||||
"ldb-test"
|
||||
"ldiff"
|
||||
"length"
|
||||
"let"
|
||||
"let*"
|
||||
"lisp-implementation-type"
|
||||
"lisp-implementation-version"
|
||||
"list"
|
||||
"list*"
|
||||
"list-all-packages"
|
||||
"list-length"
|
||||
"listen"
|
||||
"listp"
|
||||
"load"
|
||||
"load-logical-pathname-translations"
|
||||
"load-time-value"
|
||||
"locally"
|
||||
"log"
|
||||
"logand"
|
||||
"logandc1"
|
||||
"logandc2"
|
||||
"logbitp"
|
||||
"logcount"
|
||||
"logeqv"
|
||||
"logical-pathname"
|
||||
"logical-pathname-translations"
|
||||
"logior"
|
||||
"lognand"
|
||||
"lognor"
|
||||
"lognot"
|
||||
"logorc1"
|
||||
"logorc2"
|
||||
"logtest"
|
||||
"logxor"
|
||||
"long-site-name"
|
||||
"loop"
|
||||
"loop-finish"
|
||||
"lower-case-p"
|
||||
"machine-instance"
|
||||
"machine-type"
|
||||
"machine-version"
|
||||
"macro-function"
|
||||
"macroexpand"
|
||||
"macroexpand-1"
|
||||
"macrolet"
|
||||
"make-array"
|
||||
"make-broadcast-stream"
|
||||
"make-concatenated-stream"
|
||||
"make-condition"
|
||||
"make-dispatch-macro-character"
|
||||
"make-echo-stream"
|
||||
"make-hash-table"
|
||||
"make-instance"
|
||||
"make-instances-obsolete"
|
||||
"make-list"
|
||||
"make-load-form"
|
||||
"make-load-form-saving-slots"
|
||||
"make-method"
|
||||
"make-package"
|
||||
"make-pathname"
|
||||
"make-random-state"
|
||||
"make-sequence"
|
||||
"make-string"
|
||||
"make-string-input-stream"
|
||||
"make-string-output-stream"
|
||||
"make-symbol"
|
||||
"make-synonym-stream"
|
||||
"make-two-way-stream"
|
||||
"makunbound"
|
||||
"map"
|
||||
"map-into"
|
||||
"mapc"
|
||||
"mapcan"
|
||||
"mapcar"
|
||||
"mapcon"
|
||||
"maphash"
|
||||
"mapl"
|
||||
"maplist"
|
||||
"mask-field"
|
||||
"max"
|
||||
"member"
|
||||
"member-if"
|
||||
"member-if-not"
|
||||
"merge"
|
||||
"merge-pathnames"
|
||||
"method-combination-error"
|
||||
"method-qualifiers"
|
||||
"min"
|
||||
"minusp"
|
||||
"mismatch"
|
||||
"mod"
|
||||
"muffle-warning"
|
||||
"multiple-value-bind"
|
||||
"multiple-value-call"
|
||||
"multiple-value-list"
|
||||
"multiple-value-prog1"
|
||||
"multiple-value-setq"
|
||||
"name-char"
|
||||
"namestring"
|
||||
"nbutlast"
|
||||
"nconc"
|
||||
"next-method-p"
|
||||
"nintersection"
|
||||
"ninth"
|
||||
"no-applicable-method"
|
||||
"no-next-method"
|
||||
"not"
|
||||
"notany"
|
||||
"notevery"
|
||||
"nreconc"
|
||||
"nreverse"
|
||||
"nset-difference"
|
||||
"nset-exclusive-or"
|
||||
"nstring-capitalize"
|
||||
"nstring-downcase"
|
||||
"nstring-upcase"
|
||||
"nsublis"
|
||||
"nsubst"
|
||||
"nsubst-if"
|
||||
"nsubst-if-not"
|
||||
"nsubstitute"
|
||||
"nsubstitute-if"
|
||||
"nsubstitute-if-not"
|
||||
"nth"
|
||||
"nth-value"
|
||||
"nthcdr"
|
||||
"null"
|
||||
"numberp"
|
||||
"numerator"
|
||||
"nunion"
|
||||
"oddp"
|
||||
"open"
|
||||
"open-stream-p"
|
||||
"or"
|
||||
"output-stream-p"
|
||||
"package-error-package"
|
||||
"package-name"
|
||||
"package-nicknames"
|
||||
"package-shadowing-symbols"
|
||||
"package-use-list"
|
||||
"package-used-by-list"
|
||||
"packagep"
|
||||
"pairlis"
|
||||
"parse-integer"
|
||||
"parse-namestring"
|
||||
"pathname"
|
||||
"pathname-device"
|
||||
"pathname-directory"
|
||||
"pathname-host"
|
||||
"pathname-match-p"
|
||||
"pathname-name"
|
||||
"pathname-type"
|
||||
"pathname-version"
|
||||
"pathnamep"
|
||||
"peek-char"
|
||||
"phase"
|
||||
"plusp"
|
||||
"pop"
|
||||
"position"
|
||||
"position-if"
|
||||
"position-if-not"
|
||||
"pprint"
|
||||
"pprint-dispatch"
|
||||
"pprint-exit-if-list-exhausted"
|
||||
"pprint-fill"
|
||||
"pprint-indent"
|
||||
"pprint-linear"
|
||||
"pprint-logical-block"
|
||||
"pprint-newline"
|
||||
"pprint-pop"
|
||||
"pprint-tab"
|
||||
"pprint-tabular"
|
||||
"prin1"
|
||||
"prin1-to-string"
|
||||
"princ"
|
||||
"princ-to-string"
|
||||
"print"
|
||||
"print-not-readable-object"
|
||||
"print-object"
|
||||
"print-unreadable-object"
|
||||
"probe-file"
|
||||
"proclaim"
|
||||
"prog"
|
||||
"prog*"
|
||||
"prog1"
|
||||
"prog2"
|
||||
"progn"
|
||||
"progv"
|
||||
"provide"
|
||||
"psetf"
|
||||
"psetq"
|
||||
"push"
|
||||
"pushnew"
|
||||
"quote"
|
||||
"random"
|
||||
"random-state-p"
|
||||
"rassoc"
|
||||
"rassoc-if"
|
||||
"rassoc-if-not"
|
||||
"rational"
|
||||
"rationalize"
|
||||
"rationalp"
|
||||
"read"
|
||||
"read-byte"
|
||||
"read-char"
|
||||
"read-char-no-hang"
|
||||
"read-delimited-list"
|
||||
"read-from-string"
|
||||
"read-line"
|
||||
"read-preserving-whitespace"
|
||||
"read-sequence"
|
||||
"readtable-case"
|
||||
"readtablep"
|
||||
"realp"
|
||||
"realpart"
|
||||
"reduce"
|
||||
"reinitialize-instance"
|
||||
"rem"
|
||||
"remf"
|
||||
"remhash"
|
||||
"remove"
|
||||
"remove-duplicates"
|
||||
"remove-if"
|
||||
"remove-if-not"
|
||||
"remove-method"
|
||||
"remprop"
|
||||
"rename-file"
|
||||
"rename-package"
|
||||
"replace"
|
||||
"require"
|
||||
"rest"
|
||||
"restart-bind"
|
||||
"restart-case"
|
||||
"restart-name"
|
||||
"return"
|
||||
"return-from"
|
||||
"revappend"
|
||||
"reverse"
|
||||
"room"
|
||||
"rotatef"
|
||||
"round"
|
||||
"row-major-aref"
|
||||
"rplaca"
|
||||
"rplacd"
|
||||
"sbit"
|
||||
"scale-float"
|
||||
"schar"
|
||||
"search"
|
||||
"second"
|
||||
"set"
|
||||
"set-difference"
|
||||
"set-dispatch-macro-character"
|
||||
"set-exclusive-or"
|
||||
"set-macro-character"
|
||||
"set-pprint-dispatch"
|
||||
"set-syntax-from-char"
|
||||
"setf"
|
||||
"setq"
|
||||
"seventh"
|
||||
"shadow"
|
||||
"shadowing-import"
|
||||
"shared-initialize"
|
||||
"shiftf"
|
||||
"short-site-name"
|
||||
"signal"
|
||||
"signum"
|
||||
"simple-bit-vector-p"
|
||||
"simple-condition-format-arguments"
|
||||
"simple-condition-format-control"
|
||||
"simple-string-p"
|
||||
"simple-vector-p"
|
||||
"sin"
|
||||
"sinh"
|
||||
"sixth"
|
||||
"sleep"
|
||||
"slot-boundp"
|
||||
"slot-exists-p"
|
||||
"slot-makunbound"
|
||||
"slot-missing"
|
||||
"slot-unbound"
|
||||
"slot-value"
|
||||
"software-type"
|
||||
"software-version"
|
||||
"some"
|
||||
"sort"
|
||||
"special-operator-p"
|
||||
"sqrt"
|
||||
"stable-sort"
|
||||
"standard-char-p"
|
||||
"step"
|
||||
"store-value"
|
||||
"stream-element-type"
|
||||
"stream-error-stream"
|
||||
"stream-external-format"
|
||||
"streamp"
|
||||
"string"
|
||||
"string-capitalize"
|
||||
"string-downcase"
|
||||
"string-equal"
|
||||
"string-greaterp"
|
||||
"string-left-trim"
|
||||
"string-lessp"
|
||||
"string-not-equal"
|
||||
"string-not-greaterp"
|
||||
"string-not-lessp"
|
||||
"string-right-trim"
|
||||
"string-trim"
|
||||
"string-upcase"
|
||||
"string/="
|
||||
"string<"
|
||||
"string<="
|
||||
"string="
|
||||
"string>"
|
||||
"string>="
|
||||
"stringp"
|
||||
"sublis"
|
||||
"subseq"
|
||||
"subsetp"
|
||||
"subst"
|
||||
"subst-if"
|
||||
"subst-if-not"
|
||||
"substitute"
|
||||
"substitute-if"
|
||||
"substitute-if-not"
|
||||
"subtypep"
|
||||
"svref"
|
||||
"sxhash"
|
||||
"symbol-function"
|
||||
"symbol-macrolet"
|
||||
"symbol-name"
|
||||
"symbol-package"
|
||||
"symbol-plist"
|
||||
"symbol-value"
|
||||
"symbolp"
|
||||
"synonym-stream-symbol"
|
||||
"tagbody"
|
||||
"tailp"
|
||||
"tan"
|
||||
"tanh"
|
||||
"tenth"
|
||||
"terpri"
|
||||
"the"
|
||||
"third"
|
||||
"throw"
|
||||
"time"
|
||||
"trace"
|
||||
"translate-logical-pathname"
|
||||
"translate-pathname"
|
||||
"tree-equal"
|
||||
"truename"
|
||||
"truncate"
|
||||
"two-way-stream-input-stream"
|
||||
"two-way-stream-output-stream"
|
||||
"type-error-datum"
|
||||
"type-error-expected-type"
|
||||
"type-of"
|
||||
"typecase"
|
||||
"typep"
|
||||
"unbound-slot-instance"
|
||||
"unexport"
|
||||
"unintern"
|
||||
"union"
|
||||
"unless"
|
||||
"unread-char"
|
||||
"untrace"
|
||||
"unuse-package"
|
||||
"unwind-protect"
|
||||
"update-instance-for-different-class"
|
||||
"update-instance-for-redefined-class"
|
||||
"upgraded-array-element-type"
|
||||
"upgraded-complex-part-type"
|
||||
"upper-case-p"
|
||||
"use-package"
|
||||
"use-value"
|
||||
"user-homedir-pathname"
|
||||
"values"
|
||||
"values-list"
|
||||
"vector"
|
||||
"vector-pop"
|
||||
"vector-push"
|
||||
"vector-push-extend"
|
||||
"vectorp"
|
||||
"warn"
|
||||
"when"
|
||||
"wild-pathname-p"
|
||||
"with-accessors"
|
||||
"with-compilation-unit"
|
||||
"with-condition-restarts"
|
||||
"with-hash-table-iterator"
|
||||
"with-input-from-string"
|
||||
"with-open-file"
|
||||
"with-open-stream"
|
||||
"with-output-to-string"
|
||||
"with-package-iterator"
|
||||
"with-simple-restart"
|
||||
"with-slots"
|
||||
"with-standard-io-syntax"
|
||||
"write"
|
||||
"write-byte"
|
||||
"write-char"
|
||||
"write-line"
|
||||
"write-sequence"
|
||||
"write-string"
|
||||
"write-to-string"
|
||||
"y-or-n-p"
|
||||
"yes-or-no-p"
|
||||
"zerop"
|
||||
;; package :x
|
||||
"bytes-to-string"
|
||||
"d"
|
||||
"do-string"
|
||||
"do-with"
|
||||
"empty-string"
|
||||
"ensure-compiled"
|
||||
"ensure-list"
|
||||
"ends-with"
|
||||
"it"
|
||||
"it*"
|
||||
"if-it"
|
||||
"if-it*"
|
||||
"join"
|
||||
"let-it"
|
||||
"split"
|
||||
"starts-with"
|
||||
"string-split"
|
||||
"string-substitute"
|
||||
"string-to-bytes"
|
||||
"when-it"
|
||||
"when-it*"
|
||||
"while"
|
||||
"while-it"
|
||||
"with-gensyms"))
|
||||
(setf (gethash kw hash) t))
|
||||
hash)
|
||||
BIN
examples/9-simple-lisp-editor/data/local_server.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
43
examples/9-simple-lisp-editor/debug-dialog.lisp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
(defpackage :debug-dialog
|
||||
(:use :common-lisp :eql)
|
||||
(:export
|
||||
#:command))
|
||||
|
||||
(provide :debug-dialog)
|
||||
|
||||
(in-package :debug-dialog)
|
||||
|
||||
(defun command (messages font)
|
||||
(qlet ((dlg "QDialog(QWidget*,Qt::WindowFlags)" nil |Qt.WindowStaysOnTopHint|
|
||||
"windowTitle" (tr "Debug Dialog")
|
||||
"size" '(600 400))
|
||||
(msg "QTextEdit")
|
||||
(lb "QLabel" "text" (tr "Enter debug command (:h for help)"))
|
||||
(cmd "QLineEdit")
|
||||
(box "QDialogButtonBox")
|
||||
(lay "QVBoxLayout(QWidget*)" dlg))
|
||||
(x:do-with (qset msg)
|
||||
("readOnly" t)
|
||||
("font" font)
|
||||
("tabStopWidth" (qlet ((fm "QFontMetrics(QFont)" font))
|
||||
(* 8 (! "width(QChar)" fm #\Space)))))
|
||||
(x:do-with (! "addButton" box)
|
||||
|QDialogButtonBox.Ok|
|
||||
|QDialogButtonBox.Cancel|)
|
||||
(x:do-with (! "addWidget" lay)
|
||||
msg lb cmd box)
|
||||
(qset-color msg |QPalette.Base| "lightyellow")
|
||||
(qconnect box "accepted()" dlg "accept()")
|
||||
(qconnect box "rejected()" dlg "reject()")
|
||||
(! "setFocus" cmd)
|
||||
(qlater (lambda () (x:do-with dlg "activateWindow" "raise")))
|
||||
(add-messages msg messages)
|
||||
(if (= |QDialog.Accepted| (! "exec" dlg))
|
||||
(qget cmd "text")
|
||||
":r1")))
|
||||
|
||||
(defun add-messages (text-edit messages)
|
||||
(dolist (msg messages)
|
||||
(x:do-with text-edit
|
||||
("setTextColor" (cdr msg))
|
||||
("insertPlainText" (car msg)))))
|
||||
1387
examples/9-simple-lisp-editor/editor.lisp
Normal file
23
examples/9-simple-lisp-editor/exe/README.txt
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
BUILD
|
||||
=====
|
||||
|
||||
eql5 make
|
||||
qmake
|
||||
make
|
||||
|
||||
|
||||
QUIT
|
||||
====
|
||||
|
||||
See menu of "Q" system tray icon.
|
||||
|
||||
|
||||
NOTES
|
||||
=====
|
||||
|
||||
If you don't want console output, pass command line option "-silent"
|
||||
(or set "local-server::*silent*" to T).
|
||||
|
||||
Additionally, comment this line in "local_server.pro" (Windows):
|
||||
# CONFIG += console
|
||||
|
||||
13
examples/9-simple-lisp-editor/exe/local_server.pro
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
TEMPLATE = app
|
||||
CONFIG += no_keywords release
|
||||
CONFIG += console
|
||||
INCLUDEPATH += ../../../src
|
||||
LIBS += -lecl -L. -leql-local-server -L../../.. -leql5
|
||||
TARGET = eql_local_server
|
||||
DESTDIR = ./
|
||||
OBJECTS_DIR = ./tmp/
|
||||
MOC_DIR = ./tmp/
|
||||
|
||||
include(../../../src/windows.pri)
|
||||
|
||||
SOURCES += main.cpp
|
||||
27
examples/9-simple-lisp-editor/exe/main.cpp
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#include <QCoreApplication>
|
||||
#include <QTextCodec>
|
||||
#include <ecl/ecl.h>
|
||||
#include "eql.h"
|
||||
|
||||
extern "C" void ini_app(cl_object);
|
||||
|
||||
int catch_all_qexec() {
|
||||
int ret = 0;
|
||||
CL_CATCH_ALL_BEGIN(ecl_process_env()) {
|
||||
ret = QCoreApplication::exec(); }
|
||||
CL_CATCH_ALL_END;
|
||||
return ret; }
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
EQL::ini(argv);
|
||||
|
||||
QCoreApplication qapp(argc, argv);
|
||||
|
||||
QTextCodec* utf8 = QTextCodec::codecForName("UTF-8");
|
||||
QTextCodec::setCodecForLocale(utf8);
|
||||
|
||||
EQL eql;
|
||||
eql.exec(ini_app);
|
||||
|
||||
return catch_all_qexec(); }
|
||||
30
examples/9-simple-lisp-editor/exe/make.lisp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#-eql5
|
||||
(error "Please use the EQL5 executable")
|
||||
|
||||
(require :cmp)
|
||||
|
||||
#+msvc
|
||||
(setf c::*compile-in-constants* t)
|
||||
|
||||
(defparameter *lisp-files* '("input-hook"
|
||||
"top-level"
|
||||
"query-dialog"
|
||||
"debug-dialog"
|
||||
"settings"
|
||||
"local-server"))
|
||||
|
||||
(dolist (f *lisp-files*)
|
||||
(let ((file (format nil "../~A.lisp" f)))
|
||||
(load file)
|
||||
(compile-file file :system-p t)))
|
||||
|
||||
(c:build-static-library "eql-local-server"
|
||||
:lisp-files (mapcar (lambda (file)
|
||||
(format nil "../~A.~A" file #+msvc "obj" #-msvc "o"))
|
||||
*lisp-files*)
|
||||
:init-name "ini_app")
|
||||
|
||||
(dolist (file *lisp-files*)
|
||||
(delete-file (format nil "../~A.~A" file #+msvc "obj" #-msvc "o")))
|
||||
|
||||
(eql:qq)
|
||||
59
examples/9-simple-lisp-editor/input-hook.lisp
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
;;; idea & most code from "ecl-readline.lisp"
|
||||
|
||||
(defpackage input-hook
|
||||
(:use :common-lisp)
|
||||
(:export
|
||||
#:new))
|
||||
|
||||
(provide :input-hook)
|
||||
|
||||
(in-package :input-hook)
|
||||
|
||||
(defvar *functions* nil)
|
||||
|
||||
(defun new (function)
|
||||
(let ((stream (make-instance 'gray::input-hook-stream)))
|
||||
(push (cons stream function) *functions*)
|
||||
stream))
|
||||
|
||||
(in-package :gray)
|
||||
|
||||
(defclass input-hook-stream (fundamental-character-input-stream)
|
||||
((in-buffer :initform (make-string 0))
|
||||
(in-index :initform 0)
|
||||
(out-buffer :initform (make-array 0 :element-type 'character :adjustable t :fill-pointer t))))
|
||||
|
||||
(defmethod stream-read-char ((stream input-hook-stream))
|
||||
(if (ensure-stream-data stream)
|
||||
(with-slots (in-buffer in-index) stream
|
||||
(let ((ch (char in-buffer in-index)))
|
||||
(incf in-index)
|
||||
ch))
|
||||
:eof))
|
||||
|
||||
(defmethod stream-unread-char ((stream input-hook-stream) character)
|
||||
(with-slots (in-index) stream
|
||||
(when (> in-index 0)
|
||||
(decf in-index))))
|
||||
|
||||
(defmethod stream-listen ((stream input-hook-stream))
|
||||
nil)
|
||||
|
||||
(defmethod stream-clear-input ((stream input-hook-stream))
|
||||
nil)
|
||||
|
||||
(defmethod stream-close ((stream input-hook-stream) &key abort)
|
||||
(call-next-method))
|
||||
|
||||
(defmethod stream-peek-char ((stream input-hook-stream))
|
||||
(if (ensure-stream-data stream)
|
||||
(with-slots (in-buffer in-index) stream
|
||||
(char in-buffer in-index))
|
||||
:eof))
|
||||
|
||||
(defun ensure-stream-data (stream)
|
||||
(with-slots (in-buffer in-index) stream
|
||||
(when (= in-index (length in-buffer))
|
||||
(setf in-buffer (funcall (cdr (assoc stream input-hook::*functions*)))
|
||||
in-index 0))
|
||||
in-buffer))
|
||||
61
examples/9-simple-lisp-editor/local-client.lisp
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
;;; copyright (c) Polos Ruetz
|
||||
|
||||
(unless (eql:qrequire :network)
|
||||
(error "[EQL] module :network required")
|
||||
(eql:qq))
|
||||
|
||||
(defpackage :local-client
|
||||
(:use :common-lisp :eql)
|
||||
(:export
|
||||
#:*function*
|
||||
#:*server-name*
|
||||
#:ini
|
||||
#:request))
|
||||
|
||||
(provide :local-client)
|
||||
|
||||
(in-package :local-client)
|
||||
|
||||
(defvar *function* nil)
|
||||
(defvar *socket* (qnew "QLocalSocket"))
|
||||
(defvar *server-name* "EQL:local-server")
|
||||
|
||||
(defun ini (&optional fun)
|
||||
(setf *function* fun)
|
||||
(qconnect *socket* "readyRead()" 'read-data))
|
||||
|
||||
(let (size bytes-read type data)
|
||||
(defun reset-data ()
|
||||
(setf size nil
|
||||
data nil))
|
||||
(defun read-data ()
|
||||
(when *function*
|
||||
(let ((all (! "readAll" *socket*)))
|
||||
;; data may arrive splitted in more blocks
|
||||
(if size
|
||||
(when (< bytes-read size)
|
||||
(push all data)
|
||||
(incf bytes-read (length all)))
|
||||
(let* ((spc (char-code #\Space))
|
||||
(head (x:bytes-to-string (subseq all 0 (1+ (position spc all :start (1+ (position spc all)))))))
|
||||
end)
|
||||
(multiple-value-setq (size end)
|
||||
(read-from-string head))
|
||||
(multiple-value-setq (type end)
|
||||
(read-from-string head nil nil :start end))
|
||||
(push (subseq all end) data)
|
||||
(setf bytes-read (length (first data)))))
|
||||
(when (= size bytes-read)
|
||||
(funcall *function* type (qfrom-utf8 (apply 'concatenate 'vector (nreverse data))))
|
||||
(reset-data))))))
|
||||
|
||||
(defun request (str)
|
||||
(reset-data)
|
||||
(x:do-with *socket*
|
||||
("abort")
|
||||
("connectToServer" *server-name*)
|
||||
("waitForConnected"))
|
||||
(when (! "isWritable" *socket*)
|
||||
(let ((utf8 (qutf8 str)))
|
||||
(! "write(QByteArray)" *socket* (x:string-to-bytes (format nil "~D ~A" (length utf8) utf8))))
|
||||
t))
|
||||
328
examples/9-simple-lisp-editor/local-server.lisp
Normal file
|
|
@ -0,0 +1,328 @@
|
|||
;;; copyright (c) Polos Ruetz
|
||||
|
||||
#-qt-wrapper-functions ; see README-OPTIONAL.txt
|
||||
(load (in-home "src/lisp/all-wrappers"))
|
||||
|
||||
(unless (eql:qrequire :network)
|
||||
(error "[EQL] module :network required")
|
||||
(eql:qq))
|
||||
|
||||
(require :input-hook (probe-file "input-hook.lisp"))
|
||||
(require :top-level (probe-file "top-level.lisp"))
|
||||
(require :query-dialog (probe-file "query-dialog.lisp"))
|
||||
(require :debug-dialog (probe-file "debug-dialog.lisp"))
|
||||
(require :settings (probe-file "settings.lisp"))
|
||||
|
||||
(defpackage :local-server
|
||||
(:use :common-lisp :eql)
|
||||
(:export
|
||||
#:+
|
||||
#:++
|
||||
#:+++
|
||||
#:*
|
||||
#:**
|
||||
#:***
|
||||
#:/
|
||||
#://
|
||||
#:///
|
||||
#:*function*
|
||||
#:*prompt*
|
||||
#:ini
|
||||
#:clear
|
||||
#:output
|
||||
#:send-to-client))
|
||||
|
||||
(provide :local-server)
|
||||
|
||||
(in-package :local-server)
|
||||
|
||||
(defvar *function* 'feed-top-level)
|
||||
(defvar *server* (qnew "QLocalServer"))
|
||||
(defvar *client* nil)
|
||||
(defvar *prompt* t)
|
||||
(defvar *standard-output-buffer* (make-string-output-stream))
|
||||
(defvar *trace-output-buffer* (make-string-output-stream))
|
||||
(defvar *error-output-buffer* (make-string-output-stream))
|
||||
(defvar *terminal-out-buffer* (make-string-output-stream))
|
||||
(defvar *gui-debug-io* nil)
|
||||
(defvar *sharp-q* nil) ; see "CL_EQL/"
|
||||
(defvar *silent* (find "-silent" (! "arguments" "QApplication") :test 'string=))
|
||||
|
||||
;; REPL variables
|
||||
(defvar + nil)
|
||||
(defvar ++ nil)
|
||||
(defvar +++ nil)
|
||||
(defvar * nil)
|
||||
(defvar ** nil)
|
||||
(defvar *** nil)
|
||||
(defvar / nil)
|
||||
(defvar // nil)
|
||||
(defvar /// nil)
|
||||
|
||||
(defun ini (&optional (name "EQL:local-server"))
|
||||
(! "removeServer" "QLocalServer" name)
|
||||
(if (! "listen" *server* name)
|
||||
(progn
|
||||
(ini-streams)
|
||||
(set-debugger-hook)
|
||||
(setf si::*tpl-print-current-hook* 'send-file-position)
|
||||
(qset (qapp) "quitOnLastWindowClosed" nil)
|
||||
(qconnect *server* "newConnection()" 'new-client-connection)
|
||||
(multiple-value-bind (eql-version qt-version)
|
||||
(qversion)
|
||||
(format t "~%EQL local-server (EQL ~A, ECL ~A, Qt ~A)~@
|
||||
Use local-client to send input.~%"
|
||||
eql-version (lisp-implementation-version) qt-version))
|
||||
(ini-system-tray)
|
||||
t)
|
||||
(progn
|
||||
(! "critical" "QMessageBox" nil (tr "EQL local-server")
|
||||
(format nil (tr "Unable to start the server: ~A.") (! "errorString" *server*)))
|
||||
nil)))
|
||||
|
||||
(defun ini-streams ()
|
||||
(if *silent*
|
||||
(setf *standard-output* *standard-output-buffer*
|
||||
*trace-output* *trace-output-buffer*
|
||||
*error-output* *error-output-buffer*)
|
||||
(setf *standard-output* (make-broadcast-stream *standard-output*
|
||||
*standard-output-buffer*)
|
||||
*trace-output* (make-broadcast-stream *trace-output*
|
||||
*trace-output-buffer*)
|
||||
*error-output* (make-broadcast-stream *error-output*
|
||||
*error-output-buffer*)))
|
||||
(setf *terminal-io* (make-two-way-stream (two-way-stream-input-stream *terminal-io*)
|
||||
(if *silent*
|
||||
*terminal-out-buffer*
|
||||
(make-broadcast-stream (two-way-stream-output-stream *terminal-io*)
|
||||
*terminal-out-buffer*)))
|
||||
*query-io* (make-two-way-stream (input-hook:new 'handle-query-io)
|
||||
(two-way-stream-output-stream *terminal-io*))
|
||||
*gui-debug-io* (make-two-way-stream (input-hook:new 'handle-debug-io)
|
||||
(two-way-stream-output-stream *terminal-io*))))
|
||||
|
||||
(defun file-data (file)
|
||||
"To use together with '#.' reader macro, for embedding data in compiled files."
|
||||
(with-open-file (s file :direction :input :element-type '(signed-byte 8))
|
||||
(let ((data (make-array (file-length s) :element-type '(signed-byte 8))))
|
||||
(read-sequence data s)
|
||||
data)))
|
||||
|
||||
(defun ini-system-tray ()
|
||||
(let* ((tray (qnew "QSystemTrayIcon(QIcon)"
|
||||
(qnew "QIcon(QPixmap)"
|
||||
(x:let-it (qnew "QPixmap")
|
||||
(! "loadFromData" x:it
|
||||
;; embed data
|
||||
#.(file-data (in-home "examples/9-simple-lisp-editor/data/local_server.png"))
|
||||
"PNG")))))
|
||||
(menu (qnew "QMenu"))
|
||||
(quit (qnew "QAction(QObject*)" menu
|
||||
"text" (tr "Quit EQL server"))))
|
||||
(! "addAction(QAction*)" menu quit)
|
||||
(qconnect quit "triggered()" (lambda () (qdel tray) (qquit)))
|
||||
(x:do-with tray
|
||||
("setContextMenu" menu)
|
||||
("show"))))
|
||||
|
||||
(let (size bytes-read data)
|
||||
(defun reset (&optional data-only)
|
||||
(unless data-only
|
||||
(when (and *client* (not (qnull *client*)))
|
||||
(qdisconnect *client*)
|
||||
(qdel *client*)))
|
||||
(setf size nil
|
||||
data nil))
|
||||
(defun new-client-connection ()
|
||||
(reset)
|
||||
(setf *client* (! "nextPendingConnection" *server*))
|
||||
(qconnect *client* "readyRead()" 'read-from-client)
|
||||
(qconnect *client* "disconnected()" (lambda () (qdel *client* :later))))
|
||||
(defun read-from-client ()
|
||||
(when *function*
|
||||
(restart-all-timers) ; see (stop-all-timers)
|
||||
(let ((all (! "readAll" *client*)))
|
||||
;; data may arrive splitted in more blocks
|
||||
(if size
|
||||
(when (< bytes-read size)
|
||||
(push all data)
|
||||
(incf bytes-read (length all)))
|
||||
(let ((head (x:bytes-to-string (subseq all 0 (1+ (position (char-code #\Space) all)))))
|
||||
end)
|
||||
(multiple-value-setq (size end)
|
||||
(read-from-string head))
|
||||
(let ((data* (subseq all end)))
|
||||
(setf bytes-read (length data*))
|
||||
(if (and (= #.(char-code #\#) (svref data* 0))
|
||||
(= #.(char-code #\q) (svref data* 1)))
|
||||
(setf *sharp-q* t
|
||||
*print-pretty* nil ; for "CL_EQL/" return values
|
||||
eql:*break-on-errors* t
|
||||
data* (subseq data* 2))
|
||||
(setf *sharp-q* nil))
|
||||
(push data* data))))
|
||||
(when (= size bytes-read)
|
||||
(funcall *function* (qfrom-utf8 (apply 'concatenate 'vector (nreverse data))))
|
||||
(reset :data-only))))))
|
||||
|
||||
(defun current-package-name ()
|
||||
(if (eql (find-package :cl-user) *package*)
|
||||
"CL-USER"
|
||||
(car (sort (list* (package-name *package*) (package-nicknames *package*))
|
||||
(lambda (x y) (< (length x) (length y)))))))
|
||||
|
||||
(let ((n 0))
|
||||
(defun feed-top-level (str)
|
||||
(unless (x:empty-string str)
|
||||
(if *prompt*
|
||||
(let ((pkg (if (zerop n) "EQL-USER" (current-package-name)))
|
||||
(counter (princ-to-string (incf n))))
|
||||
(format t "~%~A [~A] ~A~%~A"
|
||||
pkg
|
||||
counter
|
||||
(make-string (- 50 (length counter) (length pkg)) :initial-element #\-)
|
||||
str))
|
||||
(format t "~%~A~%~%~A" #.(make-string 50 :initial-element #\_) str))
|
||||
(setf si::*read-string* str)
|
||||
(start-top-level))))
|
||||
|
||||
(defun send-output (type var)
|
||||
(let ((str (get-output-stream-string var)))
|
||||
(unless (x:empty-string str)
|
||||
(when (eql :output type)
|
||||
;; cut prompt
|
||||
(x:when-it (position #\> str)
|
||||
(setf str (subseq str (1+ x:it)))))
|
||||
(send-to-client type str))))
|
||||
|
||||
(defun start-top-level ()
|
||||
(if *sharp-q*
|
||||
(clear)
|
||||
(send-output :expression *standard-output-buffer*))
|
||||
(setf *debug-io* *gui-debug-io*)
|
||||
(clear-gui-debug-buffers)
|
||||
(si::%top-level)
|
||||
(unless *sharp-q*
|
||||
(send-output :error *error-output-buffer*)
|
||||
(send-output :trace *trace-output-buffer*)
|
||||
(send-output :output *standard-output-buffer*))
|
||||
(send-to-client :values (format nil "~{#||#~S~}" si::*latest-values*))) ; "#||#": used as separator
|
||||
|
||||
(defun clear-gui-debug-buffers ()
|
||||
(get-output-stream-string *error-output-buffer*)
|
||||
(get-output-stream-string *terminal-out-buffer*))
|
||||
|
||||
(defun clear ()
|
||||
"To use from a client to clear the output buffer. See also function OUTPUT."
|
||||
(get-output-stream-string *standard-output-buffer*))
|
||||
|
||||
(defun output ()
|
||||
"To use from a client to get the current buffer string immediately (e.g. inside a loop). See also function CLEAR."
|
||||
(send-to-client :output (get-output-stream-string *standard-output-buffer*)))
|
||||
|
||||
(defun send-file-position (file pos)
|
||||
(send-to-client :file-position (format nil "(~S . ~D)" file pos)))
|
||||
|
||||
(defun send-to-client (type &optional (str ""))
|
||||
(flet ((pause ()
|
||||
(qprocess-events)
|
||||
(sleep 0.05)))
|
||||
(when (and *client*
|
||||
(not (qnull *client*)))
|
||||
(x:while (not (zerop (! "bytesToWrite" *client*)))
|
||||
(pause))
|
||||
(if (! "isWritable" *client*)
|
||||
(let ((utf8 (qutf8 str)))
|
||||
(! "write(QByteArray)" *client* (x:string-to-bytes (format nil "~D ~S ~A" (length utf8) type utf8)))
|
||||
(pause))
|
||||
(! "critical" "QMessageBox" nil "EQL" (tr "Could not write to client."))))))
|
||||
|
||||
(defun handle-query-io ()
|
||||
(let ((txt (query-dialog:get-text (get-output-stream-string *terminal-out-buffer*))))
|
||||
(unless *sharp-q*
|
||||
(send-to-client :activate-editor))
|
||||
(send-to-client :values txt)
|
||||
(format nil "~A~%" txt)))
|
||||
|
||||
(defun handle-debug-io ()
|
||||
(stop-all-timers) ; see (restart-all-timers)
|
||||
(let ((cmd (debug-dialog:command (list (cons (get-output-stream-string *error-output-buffer*) "red")
|
||||
(cons (get-output-stream-string *terminal-out-buffer*) "black"))
|
||||
eql::*code-font*)))
|
||||
(unless *sharp-q*
|
||||
(send-to-client :activate-editor))
|
||||
(send-to-client :values "")
|
||||
(format nil "~A~%" (if (x:empty-string cmd) ":r1" cmd))))
|
||||
|
||||
(defun set-debugger-hook ()
|
||||
(setf *debugger-hook* (lambda (cond x)
|
||||
;; allow terminal input after console interrupts
|
||||
(when (eql 'si:interactive-interrupt (type-of cond))
|
||||
(setf *debug-io* *terminal-io*)))))
|
||||
|
||||
(let (timers)
|
||||
(defun stop-all-timers ()
|
||||
"Stop all timers (which need to have a parent) on errors, in order to avoid recursive debug loops. The timers will be restarted on next command from client."
|
||||
(setf timers nil)
|
||||
(dolist (w (cons (qapp) (! "allWidgets" "QApplication")))
|
||||
(dolist (o (! "children" w))
|
||||
(when (and (= #.(qid "QTimer") (qt-object-id o))
|
||||
(! "isActive" o))
|
||||
(! "stop" o)
|
||||
(push o timers)))))
|
||||
(defun restart-all-timers ()
|
||||
(dolist (timer timers)
|
||||
(! "start" timer))
|
||||
(setf timers nil)))
|
||||
|
||||
;;; extensions
|
||||
|
||||
(defun widget-selected (widget)
|
||||
(send-to-client :widget-selected (princ-to-string widget)))
|
||||
|
||||
;;; see '?' in "CL_EQL/"
|
||||
|
||||
(defvar *eval-socket* nil)
|
||||
|
||||
(defun %ini-remote-eval ()
|
||||
(unless *eval-socket*
|
||||
(setf *eval-socket* (qnew "QLocalSocket")))
|
||||
(when (= |QLocalSocket.UnconnectedState| (! "state" *eval-socket*))
|
||||
(x:do-with *eval-socket*
|
||||
("connectToServer" "EQL:eval-server")
|
||||
("waitForConnected"))))
|
||||
|
||||
(defun %remote-eval (exp)
|
||||
(%ini-remote-eval)
|
||||
(when (! "isWritable" *eval-socket*)
|
||||
(let ((utf8 (qutf8 (prin1-to-string exp))))
|
||||
(x:do-with *eval-socket*
|
||||
("write(QByteArray)" (x:string-to-bytes (format nil "~D ~A" (length utf8) utf8)))
|
||||
("waitForBytesWritten")
|
||||
("waitForReadyRead")))
|
||||
;; data may arrive splitted in more blocks
|
||||
(let* ((block-1 (! "readAll" *eval-socket*))
|
||||
(pos-space (position (char-code #\Space) block-1)))
|
||||
(when pos-space
|
||||
(let ((head (x:bytes-to-string (subseq block-1 0 (1+ pos-space))))
|
||||
data bytes-read)
|
||||
(multiple-value-bind (size end)
|
||||
(read-from-string head)
|
||||
(push (subseq block-1 end) data)
|
||||
(setf bytes-read (length (first data)))
|
||||
(x:while (< bytes-read size)
|
||||
(qprocess-events)
|
||||
(! "waitForReadyRead" *eval-socket*)
|
||||
(let ((block (! "readAll" *eval-socket*)))
|
||||
(incf bytes-read (length block))
|
||||
(push block data)))
|
||||
(unless (zerop size)
|
||||
(values (read-from-string (qfrom-utf8 (apply 'concatenate 'vector (nreverse data))))))))))))
|
||||
|
||||
#|
|
||||
(defun %log (str)
|
||||
(with-open-file (out "/tmp/log.txt" :direction :output :if-does-not-exist :create :if-exists :append)
|
||||
(format out "### ~A~%" (subseq str 0 (min (length str) 80)))))
|
||||
|#
|
||||
|
||||
(ini)
|
||||
21
examples/9-simple-lisp-editor/make-client.lisp
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#-eql5
|
||||
(error "Please use the EQL5 executable")
|
||||
|
||||
(require :cmp)
|
||||
|
||||
(defparameter *lisp-files* '("local-client"))
|
||||
|
||||
(dolist (f *lisp-files*)
|
||||
(let ((file (format nil "~A.lisp" f)))
|
||||
(load file)
|
||||
(compile-file file :system-p t)))
|
||||
|
||||
(c:build-fasl "eql-local-client"
|
||||
:lisp-files (mapcar (lambda (file)
|
||||
(format nil "~A.~A" file #+msvc "obj" #-msvc "o"))
|
||||
*lisp-files*))
|
||||
|
||||
(dolist (file *lisp-files*)
|
||||
(delete-file (format nil "~A.~A" file #+msvc "obj" #-msvc "o")))
|
||||
|
||||
(eql:qq)
|
||||
23
examples/9-simple-lisp-editor/make-editor.lisp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#-eql5
|
||||
(error "Please use the EQL5 executable")
|
||||
|
||||
(require :cmp)
|
||||
|
||||
(defparameter *lisp-files* '("local-client"
|
||||
"settings"
|
||||
"editor"))
|
||||
|
||||
(dolist (f *lisp-files*)
|
||||
(let ((file (format nil "~A.lisp" f)))
|
||||
(load file)
|
||||
(compile-file file :system-p t)))
|
||||
|
||||
(c:build-fasl "eql-editor"
|
||||
:lisp-files (mapcar (lambda (file)
|
||||
(format nil "~A.~A" file #+msvc "obj" #-msvc "o"))
|
||||
*lisp-files*))
|
||||
|
||||
(dolist (file *lisp-files*)
|
||||
(delete-file (format nil "~A.~A" file #+msvc "obj" #-msvc "o")))
|
||||
|
||||
(eql:qq)
|
||||
26
examples/9-simple-lisp-editor/make-server.lisp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#-eql5
|
||||
(error "Please use the EQL5 executable")
|
||||
|
||||
(require :cmp)
|
||||
|
||||
(defparameter *lisp-files* '("input-hook"
|
||||
"top-level"
|
||||
"query-dialog"
|
||||
"debug-dialog"
|
||||
"settings"
|
||||
"local-server"))
|
||||
|
||||
(dolist (f *lisp-files*)
|
||||
(let ((file (format nil "~A.lisp" f)))
|
||||
(load file)
|
||||
(compile-file file :system-p t)))
|
||||
|
||||
(c:build-fasl "eql-local-server"
|
||||
:lisp-files (mapcar (lambda (file)
|
||||
(format nil "~A.~A" file #+msvc "obj" #-msvc "o"))
|
||||
*lisp-files*))
|
||||
|
||||
(dolist (file *lisp-files*)
|
||||
(delete-file (format nil "~A.~A" file #+msvc "obj" #-msvc "o")))
|
||||
|
||||
(eql:qq)
|
||||
29
examples/9-simple-lisp-editor/my.lisp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
(in-package :eql-user)
|
||||
|
||||
(defvar *window* (qnew "QDialog"
|
||||
"windowTitle" "My Personal Analyst"))
|
||||
(defvar *label* (qnew "QLabel"
|
||||
"text" "Please enter your <b>Top Secret</b> (you will feel better)"))
|
||||
(defvar *line-edit* (qnew "QLineEdit"
|
||||
"echoMode" |QLineEdit.Password|))
|
||||
(defvar *layout* (qnew "QVBoxLayout(QWidget*)" *window*))
|
||||
|
||||
(defun start ()
|
||||
(x:do-with (qfun *layout* "addWidget")
|
||||
*label*
|
||||
*line-edit*)
|
||||
(qconnect *line-edit* "returnPressed()" 'analyze)
|
||||
(x:do-with *window* "show" "raise"))
|
||||
|
||||
(defun analyze ()
|
||||
(qlet ((dlg "QProgressDialog"
|
||||
"maximum" 20
|
||||
"labelText" "<h1 style='color:crimson'>Wow!</h1><p>(updating WikiLeaks...)</p>"))
|
||||
(x:do-with dlg "show" "raise")
|
||||
(dotimes (n (qget dlg "maximum"))
|
||||
(sleep 0.1)
|
||||
(qset dlg "value" n)
|
||||
(qprocess-events)))
|
||||
(qfun *line-edit* "clear"))
|
||||
|
||||
(start)
|
||||
6
examples/9-simple-lisp-editor/new.lisp
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
(defpackage :my
|
||||
(:use :common-lisp :eql)
|
||||
(:export))
|
||||
|
||||
(in-package :my)
|
||||
|
||||
25
examples/9-simple-lisp-editor/query-dialog.lisp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
(defpackage :query-dialog
|
||||
(:use :common-lisp :eql)
|
||||
(:export
|
||||
#:*default-text*
|
||||
#:get-text))
|
||||
|
||||
(provide :query-dialog)
|
||||
|
||||
(in-package :query-dialog)
|
||||
|
||||
(defvar *default-text* "")
|
||||
|
||||
(defun get-text (message)
|
||||
(qlet ((dlg "QInputDialog(QWidget*,Qt::WindowFlags)" nil |Qt.WindowStaysOnTopHint|))
|
||||
(x:do-with dlg
|
||||
("setInputMode" |QInputDialog.TextInput|)
|
||||
("setWindowTitle" (tr "Query Dialog"))
|
||||
("setLabelText" message)
|
||||
("setTextValue" *default-text*)
|
||||
("resize" '(400 0)))
|
||||
(qlater (lambda () (x:do-with dlg "activateWindow" "raise")))
|
||||
(if (= |QDialog.Accepted| (! "exec" dlg))
|
||||
(! "textValue" dlg)
|
||||
"")))
|
||||
|
||||
76
examples/9-simple-lisp-editor/send.lisp
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
;;;
|
||||
;;; Send EQL code to "local-server": a trivial one-way use of EQL from any CL
|
||||
;;;
|
||||
;;;
|
||||
;;; Run: (after building the executable in "send/")
|
||||
;;;
|
||||
;;; eql local-server.lisp
|
||||
;;; ecl -load send.lisp / clisp -i send.lisp / sbcl --load send.lisp
|
||||
;;;
|
||||
;;;
|
||||
;;; Examples: (note #!)
|
||||
;;;
|
||||
;;; #q (qmsg (package-name *package*))
|
||||
;;;
|
||||
;;; #q (qmsg #!(package-name *package*))
|
||||
;;;
|
||||
;;; (let ((a 1)
|
||||
;;; (b 2))
|
||||
;;; #q (qmsg (list #!a #!b)))
|
||||
;;;
|
||||
;;; (defun msg (x)
|
||||
;;; #q (qmsg #!x))
|
||||
;;;
|
||||
;;; #q (load "../2-clock.lisp")
|
||||
;;; #q (! "showMaximized" clock:*clock*)
|
||||
|
||||
(set-dispatch-macro-character #\# #\q (lambda (stream c n) (%read-q stream)))
|
||||
|
||||
(defmacro while-it (exp &body body)
|
||||
`(do ((it))
|
||||
((not (setf it ,exp)))
|
||||
,@body))
|
||||
|
||||
(defun %read-q (in)
|
||||
(let ((string-q (with-output-to-string (out)
|
||||
(let ((ex #\Space)
|
||||
parens in-string)
|
||||
(loop
|
||||
(let ((ch (read-char in)))
|
||||
(write-char ch out)
|
||||
(unless (char= #\\ ex)
|
||||
(if (char= #\" ch)
|
||||
(setf in-string (not in-string))
|
||||
(unless in-string
|
||||
(case ch
|
||||
(#\( (if parens (incf parens) (setf parens 1)))
|
||||
(#\) (decf parens)))
|
||||
(when (and parens (zerop parens))
|
||||
(return)))))
|
||||
(setf ex ch))))))
|
||||
list-q)
|
||||
(while-it (search "#!" string-q)
|
||||
(multiple-value-bind (exp end)
|
||||
(read-from-string (subseq string-q (+ it 2)))
|
||||
(unless (zerop it)
|
||||
(push (subseq string-q 0 it) list-q))
|
||||
(push (list 'prin1-to-string exp) list-q)
|
||||
(setf string-q (subseq string-q (+ it 2 end)))))
|
||||
(push string-q list-q)
|
||||
`(send-q (list ,@(reverse list-q)))))
|
||||
|
||||
(defun send-q (data)
|
||||
(#+ecl ext:run-program
|
||||
#+clisp run-program
|
||||
#+sbcl sb-ext:run-program
|
||||
#+darwin "./send/send.app/Contents/MacOS/send"
|
||||
#+(and unix (not darwin)) "./send/send"
|
||||
#+win32 "send/send.exe"
|
||||
#+clisp :arguments
|
||||
(list (etypecase data
|
||||
(string
|
||||
data)
|
||||
(list
|
||||
(format nil "~{~A~^ ~}" (mapcar (lambda (x) (string-trim " " x)) data)))))
|
||||
#+ecl :error #+ecl nil))
|
||||
|
||||
BIN
examples/9-simple-lisp-editor/send/send
Executable file
31
examples/9-simple-lisp-editor/send/send.cpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#include <QtCore>
|
||||
#include <QtNetwork>
|
||||
#include <QtDebug>
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
QCoreApplication qapp(argc, argv);
|
||||
QLocalSocket socket;
|
||||
socket.connectToServer("EQL:local-server");
|
||||
socket.waitForConnected();
|
||||
qapp.processEvents();
|
||||
QString exp(QCoreApplication::arguments().at(1));
|
||||
if(socket.isWritable()) {
|
||||
QString data(QString::number(exp.size()) + " " + exp);
|
||||
socket.write(data.toLatin1());
|
||||
qapp.processEvents();
|
||||
socket.waitForBytesWritten();
|
||||
while(true) {
|
||||
socket.waitForReadyRead();
|
||||
qapp.processEvents();
|
||||
QString data(socket.readAll());
|
||||
QString type(data.section(' ', 1, 1));
|
||||
if(!(":EXPRESSION" == type)) {
|
||||
QString print(data.section(' ', 2).trimmed());
|
||||
if(!print.isEmpty()) {
|
||||
std::cout << qPrintable(print) << std::endl; }
|
||||
if(":VALUES" == type) {
|
||||
exit(0); }}}}
|
||||
qCritical() << "[send] error:" << exp;
|
||||
return -1; }
|
||||
|
||||
9
examples/9-simple-lisp-editor/send/send.pro
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
QT += network
|
||||
TEMPLATE = app
|
||||
CONFIG += release
|
||||
DESTDIR = ./
|
||||
TARGET = send
|
||||
OBJECTS_DIR = ./tmp/
|
||||
MOC_DIR = ./tmp/
|
||||
|
||||
SOURCES += send.cpp
|
||||