first try
This commit is contained in:
parent
045ec51e97
commit
0ea089d432
21 changed files with 108883 additions and 2 deletions
494
README.adoc
Normal file
494
README.adoc
Normal file
|
|
@ -0,0 +1,494 @@
|
||||||
|
:experimental:
|
||||||
|
:imagesdir: http://ssalewski.de/tmp
|
||||||
|
:source-highlighter: pygments
|
||||||
|
|
||||||
|
(c) Stefan Salewski +
|
||||||
|
2017
|
||||||
|
|
||||||
|
= High level GTK3 bindings for the Nim programming language
|
||||||
|
|
||||||
|
NOTE: This work is partly based on earlier works of J. Mansour and has been supported by A. Rumpf and other Nim and GTK/Gnome developers.
|
||||||
|
The combinatorics module was kindly provided by R. Behrends.
|
||||||
|
|
||||||
|
This repository contains bindings from the Nim programming language to the GTK3 GUI library and related libraries. (With minimal fixes
|
||||||
|
it should also work for upcoming GTK4.)
|
||||||
|
|
||||||
|
https://nim-lang.org/[Nim] is a modern universal programming language.
|
||||||
|
|
||||||
|
https://www.gtk.org/[GTK], also known as the Gimp Tool Kit and now sometimes also called Gnome Tool Kit, is a Graphical User Interface library.
|
||||||
|
|
||||||
|
NOTE: Later we will insert at this location a nice picture of a fancy Nim GTK3 GUI. Such a picture is fine to attract users and indeed is a good motivation.
|
||||||
|
But such pictures are no real evidence for the quality of a GUI toolkit -- the concrete example may look nice, while the toolkit
|
||||||
|
looks much worse in other environments and offers by far not all that what is needed in real life.
|
||||||
|
|
||||||
|
While GTK was initially designed and advertised as cross platform GUI toolkit, it is currently mostly used on Linux and other Unix like operation systems.
|
||||||
|
Most Linux distributions include it, and some use it for their default desktop environment, often with the Gnome environment or other window managers.
|
||||||
|
While GTK2 applications like GIMP are still used on Windows, there seems to exist currently only very few GTK3 applications for Windows or MacOS.
|
||||||
|
When you develop primary free open source software for Linux or other Unix like Operating Systems, then GTK3 is a good choice for you. With some
|
||||||
|
effort you should be even able to port your application to the proprietary Windows or MacOS operating systems. But when your primary target platforms
|
||||||
|
are Windows and MacOS and you desire a real native look and feel there, then you may find better suited ones in the Nim software repository.
|
||||||
|
Also, when you only need a minimal restricted GUI which is very easy to install on Windows and MacOSX, then you may find better suited packages
|
||||||
|
in the Nim package repository. Android OS is currently not supported by GTK at all.
|
||||||
|
|
||||||
|
While low level Nim bindings for GTK3 are already available since a few years, this one is an attempt to
|
||||||
|
provide real high level bindings with full type safety, full Garbage Collector (GC) support and an idiomatic
|
||||||
|
application interface.
|
||||||
|
|
||||||
|
The low level bindings available at https://github.com/ngtk3 where generated with the Nim tool c2nim directly from the C header files, are already tested
|
||||||
|
with some applications (https://github.com/ngtk3/NEd[NEd Nim Editor], https://github.com/StefanSalewski/nim-chess3[Chess Game])
|
||||||
|
and generally work fine. Indeed missing Garbage Collector support is generally not really a problem, as widgets are generally
|
||||||
|
put into containers and were automatically deleted together with its parents due to GTK's reference counting.
|
||||||
|
|
||||||
|
Still there can be some demand for really high level bindings -- so this repository tries to provide them.
|
||||||
|
|
||||||
|
High level GTK3 bindings, as available for many other programming languages like Python, Ruby or D already,
|
||||||
|
would have these advantages:
|
||||||
|
|
||||||
|
* full Garbage Collector support -- you should never have to free resources manually
|
||||||
|
* Widgets are Nim objects, so inheritance and sub-classing can be used
|
||||||
|
* full type safety -- no needs for casts or other unsafe and dangerous operations
|
||||||
|
|
||||||
|
These high level bindings are based on GObject-Inrospection, an XML based database like interface description. Compared to the C header
|
||||||
|
files this description gives us more and deeper information about data types and function calls, for example ownership transfer of objects and
|
||||||
|
in or out direction of procedure variables, which makes writing the glue code much easier.
|
||||||
|
And it should work with no or minimal
|
||||||
|
modifications also for the upcoming GTK4.
|
||||||
|
|
||||||
|
Unfortunately there are also some drawbacks:
|
||||||
|
|
||||||
|
* The Application Programmer Interface (API) will be different from what is known from C API, so using C examples or C tutorials is not really straight forward
|
||||||
|
* The high level source code will differ from available C examples, so there would be a big demand for tutorials
|
||||||
|
* We need a lot of glue code, which has much room for bugs. So much testing is necessary.
|
||||||
|
* There is some overhead due to indirect calls, leading to some code size increase and minimal
|
||||||
|
performance loss.
|
||||||
|
|
||||||
|
NOTE: The new package name is "gintro", short for GObject-Introspection. The previous name was nim-gi, but the hyphen is deprecated for package names, as is the
|
||||||
|
nim prefix.
|
||||||
|
|
||||||
|
== Current state of these bindings
|
||||||
|
|
||||||
|
We are still in an early stage, but it is already more than a proof of concept. GTK and related libraries have many thousand of
|
||||||
|
callable functions and nearly as many data types. Testing all that is nearly impossible for a small team with limited resources.
|
||||||
|
The initial approach was to generate low level
|
||||||
|
bindings, which looked similar to the ones generated by the c2nim tool from the C headers. After that was done, we have associated all
|
||||||
|
the C structs and GObject data types with Nim proxy objects. A well defined relation between these proxy object and the low level C data types
|
||||||
|
should ensure fully automatic garbage collection. This is supported by smart type conversion, for example C strings returned by glib library
|
||||||
|
are assigned to newly created Nim strings, while the memory of the C strings is automatically freed. For most cases this seems to work. But there
|
||||||
|
exists a few more complicated cases, for example functions may return whole arrays of C strings or other non elementary data types,
|
||||||
|
or function arguments or results may be so called glists,
|
||||||
|
list structures of glib library. These cases can not be processed automatically but needs carefully manual investigations. And there may be still functions and data
|
||||||
|
types missing: GObject Introspection query gives us many thousand lines of Nim interface code, and it is not really obvious if and what is missing.
|
||||||
|
Some functions and data types are missing for sure -- at least some low level ones, which are considered unneeded for high level bindings by GObject-Introspection.
|
||||||
|
But maybe more is missing, we have to investigate that. Until now these bindings have been tested only for 64 bit Linux systems with GTK 3.22.
|
||||||
|
|
||||||
|
These basic libraries are already partly tested:
|
||||||
|
|
||||||
|
* GLib
|
||||||
|
* GObject
|
||||||
|
* GModule
|
||||||
|
* xlib
|
||||||
|
* Gio
|
||||||
|
* Atk
|
||||||
|
* Pango
|
||||||
|
* cairo
|
||||||
|
* GdkPixbuf
|
||||||
|
* Rsvg
|
||||||
|
* Gdk
|
||||||
|
* Gtk
|
||||||
|
|
||||||
|
In best case it should be possible to add more GObject based libraries to this list without larger modifications of the generator source code.
|
||||||
|
Unfortunately the cairo bindings provided by GObject-Introspectin are only a minimal stub -- later we will have to extend it manually.
|
||||||
|
|
||||||
|
== How to try it out
|
||||||
|
|
||||||
|
Of course you will need a working Nim installation with a recent compiler version and you have to ensure that GTK and related libraries are installed on your system. For some Linux
|
||||||
|
distributions which provide mainly pre-compiled software you may have to also install some GTK related developer files.
|
||||||
|
|
||||||
|
This package now supports the nimble package manager, so ideally a plain "nimble install gintro" should do. But as this package does not
|
||||||
|
only provide some plain text files, but uses GObject-Introspection database query on your local computer to generate
|
||||||
|
binding files exactly matching your system, that does not work currently. We have to download the files, compile and execute
|
||||||
|
the gen.nim generator program and finally to install the generates binding modules on your computer as a nimble package.
|
||||||
|
|
||||||
|
These instructions should be enough for that:
|
||||||
|
|
||||||
|
----
|
||||||
|
cd /tmp
|
||||||
|
git clone https://github.com/stefansalewski/gintro
|
||||||
|
cd gintro
|
||||||
|
nimble prepare
|
||||||
|
nimble install
|
||||||
|
----
|
||||||
|
|
||||||
|
NOTE: Nimble prepare should run for about 20 seconds, it compiles and executes the generator program gen.nim.
|
||||||
|
Unfortunately we can not guarantee that the generator command will be able to really build all the
|
||||||
|
desired modules. The built process highly depends on your OS and installed GTK version. For 64 bit Linux systems
|
||||||
|
with GTK 3.22 and all required dependencies installed it should work. For never GTK versions it may fail, when that GTK
|
||||||
|
release introduces for example new unknown data types like array containers. In that case manual fixes may be necessary.
|
||||||
|
The GObject Introspection based built process generates bindings customized to the OS where the generator is executed,
|
||||||
|
so for older GTK releases or a 32 bit system different files are created. Later we may also provide pre-generated
|
||||||
|
files for various OS and GTK versions, but building locally is preferred when possible.
|
||||||
|
|
||||||
|
Now you can built app0 and launch it:
|
||||||
|
|
||||||
|
----
|
||||||
|
cd /tmp/gintro/examples/
|
||||||
|
nim c app0.nim
|
||||||
|
./app0
|
||||||
|
----
|
||||||
|
|
||||||
|
== A few basic examples
|
||||||
|
|
||||||
|
GTK3 programs can use still the old GTK2 design, where you first initialize the GTK library, create your widgets and finally enter the GTK main loop.
|
||||||
|
This style is still used in many tutorials as in http://zetcode.com/gui/gtk2/[Zetcode tutorial] or in the GTK book of Andrew Krause.
|
||||||
|
Or you can use the new GTK3 App style, this is generally recommended by newer original GTK documentation.
|
||||||
|
Unfortunately the GTK3 original documentation is mostly restricted to the GTK3 API documentation, which is generally very good, but makes
|
||||||
|
it not very easy for beginners to start with GTK. API docs and some basic introduction is available here:
|
||||||
|
|
||||||
|
* https://www.gnome.org/
|
||||||
|
* https://www.gtk.org/
|
||||||
|
* https://developer.gnome.org/
|
||||||
|
* https://developer.gnome.org/gtk3/stable/
|
||||||
|
* https://developer.gnome.org/gtk3/stable/ch01s04.html#id-1.2.3.12.5
|
||||||
|
* https://developer.gnome.org/gnome-devel-demos/stable/c.html.en
|
||||||
|
|
||||||
|
TIP: If you should decide to continue developing software with GTK, then you should consider installing the so called
|
||||||
|
devhelp tool. It gives you easy and fast access to the API docs. For example, if you want to use a Button Widget in your
|
||||||
|
GUI and wants to learn more about related functions and signals, you just enter "Button" in that tool and are guided to
|
||||||
|
all the relevant information.
|
||||||
|
|
||||||
|
We start with a minimal traditional old style example, which should be familiar to most of us:
|
||||||
|
|
||||||
|
[source,nim]
|
||||||
|
----
|
||||||
|
# nim c t0.nim
|
||||||
|
import gtk
|
||||||
|
|
||||||
|
proc bye(w: Window) =
|
||||||
|
mainQuit()
|
||||||
|
echo "Bye..."
|
||||||
|
|
||||||
|
proc main =
|
||||||
|
gtk.init()
|
||||||
|
let window = newWindow()
|
||||||
|
window.title = "First Test"
|
||||||
|
window.connect("destroy", bye)
|
||||||
|
window.showAll
|
||||||
|
gtk.main()
|
||||||
|
|
||||||
|
main()
|
||||||
|
----
|
||||||
|
|
||||||
|
This is the traditional layout of GTK2 programs. When using this style then it is important to initialize the GTK library by calling gtk.init()
|
||||||
|
at the very beginning. Then we create the desired widgets, connect signals, show all widgets and finally enter the GTK main loop
|
||||||
|
by calling gtk.main. About connecting signals we will learn more soon, for now it is only important that we have to connect to
|
||||||
|
the destroy signal here to enable the user to terminate program execution by clicking the window close button.
|
||||||
|
|
||||||
|
Now a really minimal but complete App style example, which displays an empty window.
|
||||||
|
|
||||||
|
NOTE: The source text of all these examples is contained in the examples directory. Unfortunately github
|
||||||
|
seems to not allow to include that sources directly into this document, so there may be minimal
|
||||||
|
differences between the source code displayed here and the sources in examples directory.
|
||||||
|
|
||||||
|
[source,nim]
|
||||||
|
----
|
||||||
|
# app0.nim -- minimal application style example
|
||||||
|
# nim c app0.nim
|
||||||
|
import gtk
|
||||||
|
import gio except Application, newApplication # we want to use GTK application
|
||||||
|
#from gio import ApplicationFlags, scActivate, run
|
||||||
|
|
||||||
|
proc activate(app: Application) =
|
||||||
|
let window = newApplicationWindow(app)
|
||||||
|
window.title = "GTK3 & Nim"
|
||||||
|
window.defaultSize = (200, 200)
|
||||||
|
showAll(window)
|
||||||
|
|
||||||
|
proc main =
|
||||||
|
let app = newApplication("org.gtk.example")
|
||||||
|
connect(app, "activate", activate)
|
||||||
|
discard run(app)
|
||||||
|
|
||||||
|
main()
|
||||||
|
----
|
||||||
|
|
||||||
|
In the main proc we create a new application and connect the activate signal to our activate proc, which then creates and displays
|
||||||
|
the still empty window. For this program we need the gtk module and also some procs and types from gio module. As both modules
|
||||||
|
have a data type called Application (gtk extends indeed the gio.Application) we can either qualify the Application data type and its new proc
|
||||||
|
with gtk prefix, or as we did here, exclude that from gio imports. Another solution would be to import from gio only what is really needed.
|
||||||
|
The source code of this minimal example is stored in the examples directory, you may cd into it and type "nim c app0.nim" to create
|
||||||
|
the executable. (Well not yet, as we provide no real nimble install. Copy app0.nim to nim_gi directory where the bindings live, or
|
||||||
|
create symlinks for now.)
|
||||||
|
|
||||||
|
Various ways to set widget parameters are supported -- the number 1 to 6 refer to the comment below:
|
||||||
|
|
||||||
|
//. Setting widget parameters
|
||||||
|
[source,nim]
|
||||||
|
----
|
||||||
|
setDefaultSize(window, 200, 200) # <1>
|
||||||
|
gtk.setDefaultSize(window, 200, 200) # <2>
|
||||||
|
window.setDefaultSize(200, 200) # <3>
|
||||||
|
window.setDefaultSize(width = 200, height = 200) # <4>
|
||||||
|
window.defaultSize = (200, 200) # <5>
|
||||||
|
window.defaultSize = (width: 200, height: 200) # <6>
|
||||||
|
----
|
||||||
|
|
||||||
|
<1> proc call syntax
|
||||||
|
<2> optional qualified with module name prefix
|
||||||
|
<3> method call syntax
|
||||||
|
<4> named parameters
|
||||||
|
<5> tupel assignment
|
||||||
|
<6> tupel assignment with named members
|
||||||
|
|
||||||
|
Well, that empty window is really not very interesting. The GTK and Gnome team provides some GTK examples at https://developer.gnome.org/gnome-devel-demos/.
|
||||||
|
The https://developer.gnome.org/gnome-devel-demos/3.22/c.html.en[C demos] seems to be most actual and complete, and are easy to port to Nim. So we start with these,
|
||||||
|
but if you are familiar with the other listed languages, then you can try to port them to Nim as well. Let us start with https://developer.gnome.org/gnome-devel-demos/3.22/button.c.html.en
|
||||||
|
-- it is still short and easy to understand, but shows already some interesting topics.
|
||||||
|
|
||||||
|
image::NimGTK3Button.png[]
|
||||||
|
|
||||||
|
The C code looks like this:
|
||||||
|
|
||||||
|
[source,c]
|
||||||
|
----
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
/*This is the callback function. It is a handler function which
|
||||||
|
reacts to the signal. In this case, it will cause the button label's
|
||||||
|
string to reverse.*/
|
||||||
|
static void
|
||||||
|
button_clicked (GtkButton *button,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
const char *old_label;
|
||||||
|
char *new_label;
|
||||||
|
|
||||||
|
old_label = gtk_button_get_label (button);
|
||||||
|
new_label = g_utf8_strreverse (old_label, -1);
|
||||||
|
|
||||||
|
gtk_button_set_label (button, new_label);
|
||||||
|
g_free (new_label);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
activate (GtkApplication *app,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GtkWidget *window;
|
||||||
|
GtkWidget *button;
|
||||||
|
|
||||||
|
/*Create a window with a title and a default size*/
|
||||||
|
window = gtk_application_window_new (app);
|
||||||
|
gtk_window_set_title (GTK_WINDOW (window), "GNOME Button");
|
||||||
|
gtk_window_set_default_size (GTK_WINDOW (window), 250, 50);
|
||||||
|
|
||||||
|
/*Create a button with a label, and add it to the window*/
|
||||||
|
button = gtk_button_new_with_label ("Click Me");
|
||||||
|
gtk_container_add (GTK_CONTAINER (window), button);
|
||||||
|
|
||||||
|
/*Connecting the clicked signal to the callback function*/
|
||||||
|
g_signal_connect (GTK_BUTTON (button),
|
||||||
|
"clicked",
|
||||||
|
G_CALLBACK (button_clicked),
|
||||||
|
G_OBJECT (window));
|
||||||
|
|
||||||
|
gtk_widget_show_all (window);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char **argv)
|
||||||
|
{
|
||||||
|
GtkApplication *app;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
|
||||||
|
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
|
||||||
|
status = g_application_run (G_APPLICATION (app), argc, argv);
|
||||||
|
g_object_unref (app);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Converting it to Nim is straight forward with some basic C and Nim knowledge, and Nim does not force us
|
||||||
|
to convert its shape into all the classes known from pure object orientated languages. We can either use the
|
||||||
|
Nim tool c2nim to help us with the conversion, or do it manually. Indeed c2nim can be very helpful by
|
||||||
|
converting C sources to Nim. Most of the time it works well. Personally I generally pre-process C files, for example
|
||||||
|
by removing too strange macros and defines, or by replacing strange constructs, like C for loops, to simpler
|
||||||
|
ones like while loops. Then I apply c2nim to the C file and finally manually compare the result line by line and
|
||||||
|
fine tune the Nim code. But for this short source text we may do all that manually and finally get something like
|
||||||
|
this:
|
||||||
|
|
||||||
|
[source,nim]
|
||||||
|
----
|
||||||
|
# nim c button.nim
|
||||||
|
import gtk, glib
|
||||||
|
import gio except Application, newApplication
|
||||||
|
|
||||||
|
proc buttonClicked (button: Button) =
|
||||||
|
button.label = utf8Strreverse(button.label, -1)
|
||||||
|
|
||||||
|
proc activate (app: Application) =
|
||||||
|
let window = newApplicationWindow(app)
|
||||||
|
window.title = "GNOME Button"
|
||||||
|
window.defaultSize = (250, 50)
|
||||||
|
let button = newButton("Click Me")
|
||||||
|
window.add(button)
|
||||||
|
button.connect("clicked", buttonClicked)
|
||||||
|
window.showAll
|
||||||
|
|
||||||
|
proc main =
|
||||||
|
let app = newApplication("org.gtk.example")
|
||||||
|
connect(app, "activate", activate)
|
||||||
|
discard app.run
|
||||||
|
|
||||||
|
main()
|
||||||
|
----
|
||||||
|
|
||||||
|
Again we have the basic shape already known from app0.nim example: Main proc creates the application, connect
|
||||||
|
to the activate signal and finally runs the application. When GTK launches the application and emits the activate signal, then
|
||||||
|
our activate proc is called, which creates a main window containing a button widget. That button is again connected with a
|
||||||
|
signal, in this case named clicked. That signal is emitted by GTK whenever that button is clicked with the mouse and results
|
||||||
|
in a call of our provided buttonClicked() proc. The procs connected to signals are called callbacks and generally got the widget
|
||||||
|
on which the signal was emitted as first parameter. They can also get a second optional parameter of arbitrary type -- we will
|
||||||
|
see that in a later example. This callback here gets only the button itself as parameter, and it's task is to reverse the
|
||||||
|
text displayed by the button. Not very interesting basically, but we are indeed using the glib function utf8Strreverse()
|
||||||
|
for this task. While that function internally works with cstrings, and in C we have to free the memory of the returned cstring,
|
||||||
|
in our Nim example that is done automatically by Nim's Garbage Collector. When you compare our example carefully with the C code,
|
||||||
|
then you may notice a difference. The C code passes the window containing the button as an additional parameter to the
|
||||||
|
callback function, but that parameter is not really used. We simple ignore it here, as it is not used at all.
|
||||||
|
//and I assume that passing a widget in this way in our nim code
|
||||||
|
//may not work already currently. Fortunately widgets as optional parameter are not often needed, and we will try to make that
|
||||||
|
//working soon...
|
||||||
|
In one of the following examples you will learn how passing (nearly) arbitrary parameters in a type safe way is done.
|
||||||
|
Another difference is, that the C code returns an integer status value returned by g_application_run() to the OS. We
|
||||||
|
could do the same by using the quit() proc of Nim's OS module, but as that would give us no additional benefit, we simply ignore it.
|
||||||
|
|
||||||
|
TIP: The command nim c sourcetext.nim generates an executable which contains code for runtime checks and debugging,
|
||||||
|
which increases executable size and decreases performance.
|
||||||
|
After you have tested your software carefully, you may give the additional parameter -d:release to avoid this. For the gcc backend
|
||||||
|
you may additional enable link time optimization (LTO), which reduces executable size further. To enable LTO. you may put
|
||||||
|
a nim.cfg file in your sources directory with content like
|
||||||
|
|
||||||
|
----
|
||||||
|
path:"$projectdir"
|
||||||
|
nimcache:"/tmp/$projectdir"
|
||||||
|
gcc.options.speed = "-march=native -O3 -flto -fstrict-aliasing"
|
||||||
|
----
|
||||||
|
|
||||||
|
With that optimization, your executable sizes should be in the range of about 50 kilobyte only!
|
||||||
|
|
||||||
|
=== Optional, type safe parameters for callbacks
|
||||||
|
|
||||||
|
The next example shows, how we can pass (nearly) arbitrary parameters to our connect procs.
|
||||||
|
We pass a string, an object from the stack, a reference to an object allocated on the heap
|
||||||
|
and finally a widget (in this case the application window itself, you may also try passing
|
||||||
|
another button). As the main window itself is a so called GTK bin and can contain only one
|
||||||
|
child widget, we create a container widget, a vertical box in this case, fill that box with
|
||||||
|
some buttons, and add that button to the window.
|
||||||
|
|
||||||
|
Compile and start this example from the command line and watch what
|
||||||
|
happens when you click on the buttons.
|
||||||
|
|
||||||
|
[source,nim]
|
||||||
|
----
|
||||||
|
# nim c connect_args.nim
|
||||||
|
import gtk, glib
|
||||||
|
import gio except Application, newApplication
|
||||||
|
|
||||||
|
type
|
||||||
|
O = object
|
||||||
|
i: int
|
||||||
|
|
||||||
|
proc b1Callback(button: Button; str: string) =
|
||||||
|
echo str
|
||||||
|
|
||||||
|
proc b2Callback(button: Button; o: O) =
|
||||||
|
echo "Value of field i in object o = ", o.i
|
||||||
|
|
||||||
|
proc b3Callback(button: Button; r: ref O) =
|
||||||
|
echo "Value of field i in ref to object O = ", r.i
|
||||||
|
|
||||||
|
proc b4Callback(button: Button; w: ApplicationWindow) =
|
||||||
|
if w.title == "Nim with GTK3":
|
||||||
|
w.title = "GTK3 with Nim"
|
||||||
|
else:
|
||||||
|
w.title = "Nim with GTK3"
|
||||||
|
|
||||||
|
proc activate (app: Application) =
|
||||||
|
var o: O
|
||||||
|
var r: ref O
|
||||||
|
new r
|
||||||
|
o.i = 1234567
|
||||||
|
r.i = 7654321
|
||||||
|
let window = newApplicationWindow(app)
|
||||||
|
let box = newBox(Orientation.vertical, 0)
|
||||||
|
window.title = "Parameters for callbacks"
|
||||||
|
let b1 = newButton("Nim with GTK3")
|
||||||
|
let b2 = newButton("Passing an object from stack")
|
||||||
|
let b3 = newButton("Passing an object from heap")
|
||||||
|
let b4 = newButton("Passing a Widget")
|
||||||
|
b1.connect("clicked", b1Callback, "is much fun.")
|
||||||
|
b2.connect("clicked", b2Callback, o)
|
||||||
|
b3.connect("clicked", b3Callback, r)
|
||||||
|
b4.connect("clicked", b4Callback, window)
|
||||||
|
box.add(b1)
|
||||||
|
box.add(b2)
|
||||||
|
box.add(b3)
|
||||||
|
box.add(b4)
|
||||||
|
window.add(box)
|
||||||
|
window.showAll
|
||||||
|
|
||||||
|
proc main =
|
||||||
|
let app = newApplication("org.gtk.example")
|
||||||
|
connect(app, "activate", activate)
|
||||||
|
discard app.run
|
||||||
|
|
||||||
|
main()
|
||||||
|
----
|
||||||
|
|
||||||
|
To prove type safety, we may modify one of the callback procs and watch the compiler output:
|
||||||
|
|
||||||
|
[source,c]
|
||||||
|
----
|
||||||
|
proc b1Callback(button: Button; str: int) =
|
||||||
|
discard # echo str
|
||||||
|
----
|
||||||
|
|
||||||
|
----
|
||||||
|
connect_args.nim(37, 5) template/generic instantiation from here
|
||||||
|
gtk.nim(-15021, 10) Error: type mismatch: got (ref Button:ObjectType, string)
|
||||||
|
but expected one of:
|
||||||
|
proc b1Callback(button: Button; str: int)
|
||||||
|
----
|
||||||
|
|
||||||
|
It may be not always really obvious what the compiler wants to tell us, but at least we
|
||||||
|
are told that it got a string and expected an int.
|
||||||
|
|
||||||
|
Currently the connect function is realized by a Nim type safe macro. Connect accepts two or three
|
||||||
|
arguments -- the widget, the signal name and the optional argument. When the optional argument
|
||||||
|
is a ref (reference to objects on the heap) then it is passed as a reference, otherwise a deep copy
|
||||||
|
of the argument is passed. For the above code this means, that r and the window are passed
|
||||||
|
as references, while the string and the stack object are deep copied. Currently it is not possible
|
||||||
|
to release the memory of passed arguments again. This should be no real problem, as in most
|
||||||
|
cases no arguments are passed at all, and when arguments are passed, then they are general
|
||||||
|
small in size like plain numbers or strings, or maybe references to widgets which could not be freed
|
||||||
|
at all, as they are part of the GUI. Later we may add more variants of that connect macro.
|
||||||
|
|
||||||
|
NOTE: Navigation can be hard for beginners. You may have basic knowledge of GTK and want
|
||||||
|
to build a GUI for your application. But how to find what you need. Well, we offer no separate
|
||||||
|
automatically generated API documentation currently, as that is not really helpful. In most cases
|
||||||
|
it is easy to just guess Nim symbol names, proc parameters and all that. Using a smart editor
|
||||||
|
with good nimsuggest support further supports navigation -- for example NEd shows us
|
||||||
|
all the needed proc parameters when we move the cursor on a proc name, or we press CTRL-W and jump
|
||||||
|
to the definition of that symbol. For unknown stuff the original C function name is often a good starting point.
|
||||||
|
Assume you don't know much about GTK's buttons, but you know that you want to have a Button in
|
||||||
|
your GUI application. GTK generally offers generator functions containing the string "new" in their name.
|
||||||
|
So it is easy to guess that there exists a C function named "gtk_button_new". That name is also
|
||||||
|
contained in the bindings files, in this case in gtk.nim. So we open that file in a text editor and search for
|
||||||
|
that term. So it is really easy to find first starting points for related procs and data types. Most data types
|
||||||
|
are located near by their related functions, so you should be able to find all relevant information fast.
|
||||||
|
Remember the GTK devhelp tool, and use also grep or the nim-grep variant.
|
||||||
|
|
||||||
|
NOTE: Related work: https://github.com/jdmansour/nim-smartgi
|
||||||
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
# gintro
|
|
||||||
High level GObject-Introspection based GTK3 bindings for Nim language
|
|
||||||
18
examples/app0.nim
Normal file
18
examples/app0.nim
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# app0.nim -- minimal application style example
|
||||||
|
# nim c app0.nim
|
||||||
|
import gintro/gtk
|
||||||
|
import gintro/gio except Application, newApplication # we want to use GTK application
|
||||||
|
#from gintro/gio import ApplicationFlags, scActivate, run
|
||||||
|
|
||||||
|
proc activate(app: Application) =
|
||||||
|
let window = newApplicationWindow(app)
|
||||||
|
window.title = "GTK3 & Nim"
|
||||||
|
window.defaultSize = (200, 200)
|
||||||
|
showAll(window)
|
||||||
|
|
||||||
|
proc main =
|
||||||
|
let app = newApplication("org.gtk.example")
|
||||||
|
connect(app, "activate", activate)
|
||||||
|
discard run(app)
|
||||||
|
|
||||||
|
main()
|
||||||
23
examples/button.nim
Normal file
23
examples/button.nim
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
# nim c button.nim
|
||||||
|
import gintro/[gtk, glib]
|
||||||
|
import gintro/gio except Application, newApplication
|
||||||
|
|
||||||
|
proc buttonClicked (button: Button) =
|
||||||
|
button.label = utf8Strreverse(button.label, -1)
|
||||||
|
|
||||||
|
proc activate (app: Application) =
|
||||||
|
let window = newApplicationWindow(app)
|
||||||
|
window.title = "GNOME Button"
|
||||||
|
window.defaultSize = (250, 50)
|
||||||
|
let button = newButton("Click Me")
|
||||||
|
window.add(button)
|
||||||
|
button.connect("clicked", buttonClicked)
|
||||||
|
window.showAll
|
||||||
|
|
||||||
|
proc main =
|
||||||
|
let app = newApplication("org.gtk.example")
|
||||||
|
connect(app, "activate", activate)
|
||||||
|
discard app.run
|
||||||
|
|
||||||
|
main()
|
||||||
|
|
||||||
54
examples/connect_args.nim
Normal file
54
examples/connect_args.nim
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
# nim c connect_args.nim
|
||||||
|
import gintro/[gtk, glib]
|
||||||
|
import gintro/gio except Application, newApplication
|
||||||
|
|
||||||
|
type
|
||||||
|
O = object
|
||||||
|
i: int
|
||||||
|
|
||||||
|
proc b1Callback(button: Button; str: string) =
|
||||||
|
echo str
|
||||||
|
|
||||||
|
proc b2Callback(button: Button; o: O) =
|
||||||
|
echo "Value of field i in object o = ", o.i
|
||||||
|
|
||||||
|
proc b3Callback(button: Button; r: ref O) =
|
||||||
|
echo "Value of field i in ref to object O = ", r.i
|
||||||
|
|
||||||
|
proc b4Callback(button: Button; w: ApplicationWindow) =
|
||||||
|
if w.title == "Nim with GTK3":
|
||||||
|
w.title = "GTK3 with Nim"
|
||||||
|
else:
|
||||||
|
w.title = "Nim with GTK3"
|
||||||
|
|
||||||
|
proc activate (app: Application) =
|
||||||
|
var o: O
|
||||||
|
var r: ref O
|
||||||
|
new r
|
||||||
|
o.i = 1234567
|
||||||
|
r.i = 7654321
|
||||||
|
let window = newApplicationWindow(app)
|
||||||
|
let box = newBox(Orientation.vertical, 0)
|
||||||
|
window.title = "Parameters for callbacks"
|
||||||
|
let b1 = newButton("Nim with GTK3")
|
||||||
|
let b2 = newButton("Passing an object from stack")
|
||||||
|
let b3 = newButton("Passing an object from heap")
|
||||||
|
let b4 = newButton("Passing a Widget")
|
||||||
|
b1.connect("clicked", b1Callback, "is much fun.")
|
||||||
|
b2.connect("clicked", b2Callback, o)
|
||||||
|
b3.connect("clicked", b3Callback, r)
|
||||||
|
b4.connect("clicked", b4Callback, window)
|
||||||
|
box.add(b1)
|
||||||
|
box.add(b2)
|
||||||
|
box.add(b3)
|
||||||
|
box.add(b4)
|
||||||
|
window.add(box)
|
||||||
|
window.showAll
|
||||||
|
|
||||||
|
proc main =
|
||||||
|
let app = newApplication("org.gtk.example")
|
||||||
|
connect(app, "activate", activate)
|
||||||
|
discard app.run
|
||||||
|
|
||||||
|
main()
|
||||||
|
|
||||||
16
examples/t0.nim
Normal file
16
examples/t0.nim
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
# nim c t0.nim
|
||||||
|
import gintro/gtk
|
||||||
|
|
||||||
|
proc bye(w: Window) =
|
||||||
|
mainQuit()
|
||||||
|
echo "Bye..."
|
||||||
|
|
||||||
|
proc main =
|
||||||
|
gtk.init()
|
||||||
|
let window = newWindow()
|
||||||
|
window.title = "First Test"
|
||||||
|
window.connect("destroy", bye)
|
||||||
|
window.showAll
|
||||||
|
gtk.main()
|
||||||
|
|
||||||
|
main()
|
||||||
65
gintro.nimble
Normal file
65
gintro.nimble
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
# Package
|
||||||
|
|
||||||
|
version = "0.1.0"
|
||||||
|
author = "Stefan Salewski"
|
||||||
|
description = "High level GObject-Introspection based GTK3 bindings"
|
||||||
|
license = "MIT"
|
||||||
|
skipDirs = @["tests"]
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
|
|
||||||
|
requires "nim >= 0.17.0"
|
||||||
|
|
||||||
|
when defined(nimdistros):
|
||||||
|
import distros
|
||||||
|
if detectOs(Ubuntu) or detectOs(Debian):
|
||||||
|
foreignDep "libgtk-3-dev"
|
||||||
|
elif detectOs(Gentoo):
|
||||||
|
foreignDep "gtk+" # can we specify gtk3?
|
||||||
|
#else: we don't know the names for all the other distributions
|
||||||
|
# foreignDep "openssl"
|
||||||
|
|
||||||
|
import ospaths
|
||||||
|
|
||||||
|
proc prep =
|
||||||
|
let this = thisDir()
|
||||||
|
let td = getTempDir()
|
||||||
|
cd(td)
|
||||||
|
let wd = "gintrosalewski"
|
||||||
|
if dirExists(wd):
|
||||||
|
quit("gintro: tmp directory already exists!")
|
||||||
|
mkDir(wd)
|
||||||
|
cd(wd)
|
||||||
|
mkDir("ngtk3")
|
||||||
|
cd("ngtk3")
|
||||||
|
|
||||||
|
exec("git clone https://github.com/ngtk3/nim-glib")
|
||||||
|
exec("git clone https://github.com/ngtk3/nim-gobject")
|
||||||
|
exec("git clone https://github.com/ngtk3/nim-gir")
|
||||||
|
|
||||||
|
cpFile(this / "tests" / "gen.nim", td / wd / "gen.nim")
|
||||||
|
cpFile(this / "tests" / "combinatorics.nim", td / wd / "combinatorics.nim")
|
||||||
|
|
||||||
|
cpFile("nim-glib/src/glib.nim", td / wd / "glib.nim")
|
||||||
|
cpFile("nim-gobject/src/gobject.nim", td / wd / "gobject.nim")
|
||||||
|
cpFile("nim-gir/src/gir.nim", td / wd / "gir.nim")
|
||||||
|
|
||||||
|
cd(td)
|
||||||
|
cd(wd)
|
||||||
|
exec("nim c gen.nim")
|
||||||
|
mkDir("nim_gi")
|
||||||
|
exec(td / wd / "gen")
|
||||||
|
let mods = listFiles("nim_gi")
|
||||||
|
for i in mods:
|
||||||
|
let j = i[7 .. ^1]
|
||||||
|
cpFile(i, this / "gintro" / j)
|
||||||
|
cd(td)
|
||||||
|
rmDir(wd) # cleanup
|
||||||
|
|
||||||
|
task prepare, "preparing gintro":
|
||||||
|
#before install:
|
||||||
|
|
||||||
|
echo "preparing gintro"
|
||||||
|
prep()
|
||||||
|
|
||||||
|
|
||||||
3706
gintro/atk.nim
Normal file
3706
gintro/atk.nim
Normal file
File diff suppressed because it is too large
Load diff
80
gintro/cairo.nim
Normal file
80
gintro/cairo.nim
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
# dependencies:
|
||||||
|
# immediate dependencies:
|
||||||
|
# libraries:
|
||||||
|
# libcairo-gobject.so.2
|
||||||
|
{.deadCodeElim: on.}
|
||||||
|
|
||||||
|
const Lib* = "libcairo-gobject.so.2"
|
||||||
|
{.pragma: libprag, cdecl, dynlib: Lib.}
|
||||||
|
|
||||||
|
type
|
||||||
|
Context00* {.pure.} = object
|
||||||
|
Context* = ref object
|
||||||
|
impl*: ptr Context00
|
||||||
|
|
||||||
|
type
|
||||||
|
Surface00* {.pure.} = object
|
||||||
|
Surface* = ref object
|
||||||
|
impl*: ptr Surface00
|
||||||
|
|
||||||
|
type
|
||||||
|
Matrix00* {.pure.} = object
|
||||||
|
Matrix* = ref object
|
||||||
|
impl*: ptr Matrix00
|
||||||
|
|
||||||
|
type
|
||||||
|
Pattern00* {.pure.} = object
|
||||||
|
Pattern* = ref object
|
||||||
|
impl*: ptr Pattern00
|
||||||
|
|
||||||
|
type
|
||||||
|
Region00* {.pure.} = object
|
||||||
|
Region* = ref object
|
||||||
|
impl*: ptr Region00
|
||||||
|
|
||||||
|
type
|
||||||
|
Content* {.size: sizeof(cint), pure.} = enum
|
||||||
|
COLOR = 4096
|
||||||
|
ALPHA = 8192
|
||||||
|
COLOR_ALPHA = 12288
|
||||||
|
|
||||||
|
type
|
||||||
|
FontOptions00* {.pure.} = object
|
||||||
|
FontOptions* = ref object
|
||||||
|
impl*: ptr FontOptions00
|
||||||
|
|
||||||
|
type
|
||||||
|
FontType00* {.pure.} = object
|
||||||
|
FontType* = ref object
|
||||||
|
impl*: ptr FontType00
|
||||||
|
|
||||||
|
type
|
||||||
|
FontFace00* {.pure.} = object
|
||||||
|
FontFace* = ref object
|
||||||
|
impl*: ptr FontFace00
|
||||||
|
|
||||||
|
type
|
||||||
|
ScaledFont00* {.pure.} = object
|
||||||
|
ScaledFont* = ref object
|
||||||
|
impl*: ptr ScaledFont00
|
||||||
|
|
||||||
|
type
|
||||||
|
Path00* {.pure.} = object
|
||||||
|
Path* = ref object
|
||||||
|
impl*: ptr Path00
|
||||||
|
|
||||||
|
type
|
||||||
|
RectangleInt00* {.pure.} = object
|
||||||
|
x*: int32
|
||||||
|
y*: int32
|
||||||
|
width*: int32
|
||||||
|
height*: int32
|
||||||
|
RectangleInt* = ref object
|
||||||
|
impl*: ptr RectangleInt00
|
||||||
|
|
||||||
|
proc cairo_image_surface_create*() {.
|
||||||
|
importc: "cairo_image_surface_create", libprag.}
|
||||||
|
|
||||||
|
proc imageSurfaceCreate*() {.
|
||||||
|
importc: "cairo_image_surface_create", libprag.}
|
||||||
|
# === remaining symbols:
|
||||||
12452
gintro/gdk.nim
Normal file
12452
gintro/gdk.nim
Normal file
File diff suppressed because it is too large
Load diff
1565
gintro/gdkpixbuf.nim
Normal file
1565
gintro/gdkpixbuf.nim
Normal file
File diff suppressed because it is too large
Load diff
21398
gintro/gio.nim
Normal file
21398
gintro/gio.nim
Normal file
File diff suppressed because it is too large
Load diff
10450
gintro/glib.nim
Normal file
10450
gintro/glib.nim
Normal file
File diff suppressed because it is too large
Load diff
75
gintro/gmodule.nim
Normal file
75
gintro/gmodule.nim
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
# dependencies:
|
||||||
|
# GLib-2.0
|
||||||
|
# immediate dependencies:
|
||||||
|
# GLib-2.0
|
||||||
|
# libraries:
|
||||||
|
# libgmodule-2.0.so.0
|
||||||
|
{.deadCodeElim: on.}
|
||||||
|
import glib
|
||||||
|
const Lib* = "libgmodule-2.0.so.0"
|
||||||
|
{.pragma: libprag, cdecl, dynlib: Lib.}
|
||||||
|
let Quark = g_quark_from_static_string("NimGIQuark")
|
||||||
|
|
||||||
|
type
|
||||||
|
Module00* {.pure.} = object
|
||||||
|
Module* = ref object
|
||||||
|
impl*: ptr Module00
|
||||||
|
|
||||||
|
proc g_module_close*(self: ptr Module00): gboolean {.
|
||||||
|
importc: "g_module_close", libprag.}
|
||||||
|
|
||||||
|
proc close*(self: Module): bool =
|
||||||
|
toBool(g_module_close(cast[ptr Module00](self.impl)))
|
||||||
|
|
||||||
|
proc g_module_make_resident*(self: ptr Module00) {.
|
||||||
|
importc: "g_module_make_resident", libprag.}
|
||||||
|
|
||||||
|
proc makeResident*(self: Module) =
|
||||||
|
g_module_make_resident(cast[ptr Module00](self.impl))
|
||||||
|
|
||||||
|
proc g_module_name*(self: ptr Module00): cstring {.
|
||||||
|
importc: "g_module_name", libprag.}
|
||||||
|
|
||||||
|
proc name*(self: Module): string =
|
||||||
|
let resul0 = g_module_name(cast[ptr Module00](self.impl))
|
||||||
|
result = $resul0
|
||||||
|
|
||||||
|
proc g_module_symbol*(self: ptr Module00; symbolName: cstring; symbol: var pointer): gboolean {.
|
||||||
|
importc: "g_module_symbol", libprag.}
|
||||||
|
|
||||||
|
proc symbol*(self: Module; symbolName: string; symbol: var pointer): bool =
|
||||||
|
toBool(g_module_symbol(cast[ptr Module00](self.impl), cstring(symbolName), symbol))
|
||||||
|
|
||||||
|
proc g_module_build_path*(directory: cstring; moduleName: cstring): cstring {.
|
||||||
|
importc: "g_module_build_path", libprag.}
|
||||||
|
|
||||||
|
proc buildPath*(directory: string; moduleName: string): string =
|
||||||
|
let resul0 = g_module_build_path(cstring(directory), cstring(moduleName))
|
||||||
|
result = $resul0
|
||||||
|
cogfree(resul0)
|
||||||
|
|
||||||
|
proc g_module_error*(): cstring {.
|
||||||
|
importc: "g_module_error", libprag.}
|
||||||
|
|
||||||
|
proc error*(): string =
|
||||||
|
let resul0 = g_module_error()
|
||||||
|
result = $resul0
|
||||||
|
|
||||||
|
proc g_module_supported*(): gboolean {.
|
||||||
|
importc: "g_module_supported", libprag.}
|
||||||
|
|
||||||
|
proc supported*(): gboolean {.
|
||||||
|
importc: "g_module_supported", libprag.}
|
||||||
|
|
||||||
|
type
|
||||||
|
ModuleCheckInit* = proc (module: ptr Module00): cstring {.cdecl.}
|
||||||
|
|
||||||
|
type
|
||||||
|
ModuleFlags* {.size: sizeof(cint), pure.} = enum
|
||||||
|
lazy = 1
|
||||||
|
local = 2
|
||||||
|
mask = 3
|
||||||
|
|
||||||
|
type
|
||||||
|
ModuleUnload* = proc (module: ptr Module00) {.cdecl.}
|
||||||
|
# === remaining symbols:
|
||||||
2162
gintro/gobject.nim
Normal file
2162
gintro/gobject.nim
Normal file
File diff suppressed because it is too large
Load diff
50546
gintro/gtk.nim
Normal file
50546
gintro/gtk.nim
Normal file
File diff suppressed because it is too large
Load diff
3884
gintro/pango.nim
Normal file
3884
gintro/pango.nim
Normal file
File diff suppressed because it is too large
Load diff
428
gintro/rsvg.nim
Normal file
428
gintro/rsvg.nim
Normal file
|
|
@ -0,0 +1,428 @@
|
||||||
|
# dependencies:
|
||||||
|
# cairo-1.0
|
||||||
|
# GLib-2.0
|
||||||
|
# Gio-2.0
|
||||||
|
# GObject-2.0
|
||||||
|
# GModule-2.0
|
||||||
|
# GdkPixbuf-2.0
|
||||||
|
# immediate dependencies:
|
||||||
|
# cairo-1.0
|
||||||
|
# Gio-2.0
|
||||||
|
# GdkPixbuf-2.0
|
||||||
|
# GObject-2.0
|
||||||
|
# GLib-2.0
|
||||||
|
# libraries:
|
||||||
|
# librsvg-2.so.2
|
||||||
|
{.deadCodeElim: on.}
|
||||||
|
import cairo, glib, gio, gobject, gmodule, gdkpixbuf
|
||||||
|
const Lib* = "librsvg-2.so.2"
|
||||||
|
{.pragma: libprag, cdecl, dynlib: Lib.}
|
||||||
|
let Quark = g_quark_from_static_string("NimGIQuark")
|
||||||
|
|
||||||
|
type
|
||||||
|
DimensionData00* {.pure.} = object
|
||||||
|
width*: int32
|
||||||
|
height*: int32
|
||||||
|
em*: cdouble
|
||||||
|
ex*: cdouble
|
||||||
|
DimensionData* = ref object
|
||||||
|
impl*: ptr DimensionData00
|
||||||
|
|
||||||
|
type
|
||||||
|
Error* {.size: sizeof(cint), pure.} = enum
|
||||||
|
errorFailed = 0
|
||||||
|
|
||||||
|
type
|
||||||
|
HandlePrivate00* {.pure.} = object
|
||||||
|
HandlePrivate* = ref object
|
||||||
|
impl*: ptr HandlePrivate00
|
||||||
|
|
||||||
|
type
|
||||||
|
Handle* = ref object of gobject.Object
|
||||||
|
Handle00* = object of gobject.Object00
|
||||||
|
priv1: ptr HandlePrivate00
|
||||||
|
abiPadding*: array[15, pointer]
|
||||||
|
|
||||||
|
proc rsvg_handle_new*(): ptr Handle00 {.
|
||||||
|
importc: "rsvg_handle_new", libprag.}
|
||||||
|
|
||||||
|
proc newHandle*(): Handle =
|
||||||
|
new(result, finalizeGObject)
|
||||||
|
result.impl = rsvg_handle_new()
|
||||||
|
GC_ref(result)
|
||||||
|
discard g_object_ref_sink(result.impl)
|
||||||
|
g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))
|
||||||
|
g_object_unref(result.impl)
|
||||||
|
assert(g_object_get_qdata(result.impl, Quark) == nil)
|
||||||
|
g_object_set_qdata(result.impl, Quark, addr(result[]))
|
||||||
|
|
||||||
|
proc initHandle*[T](result: var T) =
|
||||||
|
assert(result is Handle)
|
||||||
|
new(result, finalizeGObject)
|
||||||
|
result.impl = rsvg_handle_new()
|
||||||
|
GC_ref(result)
|
||||||
|
discard g_object_ref_sink(result.impl)
|
||||||
|
g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))
|
||||||
|
g_object_unref(result.impl)
|
||||||
|
assert(g_object_get_qdata(result.impl, Quark) == nil)
|
||||||
|
g_object_set_qdata(result.impl, Quark, addr(result[]))
|
||||||
|
|
||||||
|
proc rsvg_handle_new_from_data*(data: uint8Array; dataLen: uint64): ptr Handle00 {.
|
||||||
|
importc: "rsvg_handle_new_from_data", libprag.}
|
||||||
|
|
||||||
|
proc newHandleFromData*(data: uint8Array; dataLen: uint64): Handle =
|
||||||
|
new(result, finalizeGObject)
|
||||||
|
result.impl = rsvg_handle_new_from_data(data, dataLen)
|
||||||
|
GC_ref(result)
|
||||||
|
discard g_object_ref_sink(result.impl)
|
||||||
|
g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))
|
||||||
|
g_object_unref(result.impl)
|
||||||
|
assert(g_object_get_qdata(result.impl, Quark) == nil)
|
||||||
|
g_object_set_qdata(result.impl, Quark, addr(result[]))
|
||||||
|
|
||||||
|
proc initHandleFromData*[T](result: var T; data: uint8Array; dataLen: uint64) =
|
||||||
|
assert(result is Handle)
|
||||||
|
new(result, finalizeGObject)
|
||||||
|
result.impl = rsvg_handle_new_from_data(data, dataLen)
|
||||||
|
GC_ref(result)
|
||||||
|
discard g_object_ref_sink(result.impl)
|
||||||
|
g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))
|
||||||
|
g_object_unref(result.impl)
|
||||||
|
assert(g_object_get_qdata(result.impl, Quark) == nil)
|
||||||
|
g_object_set_qdata(result.impl, Quark, addr(result[]))
|
||||||
|
|
||||||
|
proc rsvg_handle_new_from_file*(fileName: cstring): ptr Handle00 {.
|
||||||
|
importc: "rsvg_handle_new_from_file", libprag.}
|
||||||
|
|
||||||
|
proc newHandleFromFile*(fileName: string): Handle =
|
||||||
|
new(result, finalizeGObject)
|
||||||
|
result.impl = rsvg_handle_new_from_file(cstring(fileName))
|
||||||
|
GC_ref(result)
|
||||||
|
discard g_object_ref_sink(result.impl)
|
||||||
|
g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))
|
||||||
|
g_object_unref(result.impl)
|
||||||
|
assert(g_object_get_qdata(result.impl, Quark) == nil)
|
||||||
|
g_object_set_qdata(result.impl, Quark, addr(result[]))
|
||||||
|
|
||||||
|
proc initHandleFromFile*[T](result: var T; fileName: string) =
|
||||||
|
assert(result is Handle)
|
||||||
|
new(result, finalizeGObject)
|
||||||
|
result.impl = rsvg_handle_new_from_file(cstring(fileName))
|
||||||
|
GC_ref(result)
|
||||||
|
discard g_object_ref_sink(result.impl)
|
||||||
|
g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))
|
||||||
|
g_object_unref(result.impl)
|
||||||
|
assert(g_object_get_qdata(result.impl, Quark) == nil)
|
||||||
|
g_object_set_qdata(result.impl, Quark, addr(result[]))
|
||||||
|
|
||||||
|
proc rsvg_handle_close*(self: ptr Handle00): gboolean {.
|
||||||
|
importc: "rsvg_handle_close", libprag.}
|
||||||
|
|
||||||
|
proc close*(self: Handle): bool =
|
||||||
|
toBool(rsvg_handle_close(cast[ptr Handle00](self.impl)))
|
||||||
|
|
||||||
|
proc rsvg_handle_get_base_uri*(self: ptr Handle00): cstring {.
|
||||||
|
importc: "rsvg_handle_get_base_uri", libprag.}
|
||||||
|
|
||||||
|
proc getBaseUri*(self: Handle): string =
|
||||||
|
let resul0 = rsvg_handle_get_base_uri(cast[ptr Handle00](self.impl))
|
||||||
|
result = $resul0
|
||||||
|
|
||||||
|
proc baseUri*(self: Handle): string =
|
||||||
|
let resul0 = rsvg_handle_get_base_uri(cast[ptr Handle00](self.impl))
|
||||||
|
result = $resul0
|
||||||
|
|
||||||
|
proc rsvg_handle_get_dimensions*(self: ptr Handle00; dimensionData: var DimensionData00) {.
|
||||||
|
importc: "rsvg_handle_get_dimensions", libprag.}
|
||||||
|
|
||||||
|
proc getDimensions*(self: ptr Handle00; dimensionData: var DimensionData00) {.
|
||||||
|
importc: "rsvg_handle_get_dimensions", libprag.}
|
||||||
|
|
||||||
|
proc dimensions*(self: ptr Handle00; dimensionData: var DimensionData00) {.
|
||||||
|
importc: "rsvg_handle_get_dimensions", libprag.}
|
||||||
|
|
||||||
|
proc rsvg_handle_get_dimensions_sub*(self: ptr Handle00; dimensionData: var DimensionData00;
|
||||||
|
id: cstring): gboolean {.
|
||||||
|
importc: "rsvg_handle_get_dimensions_sub", libprag.}
|
||||||
|
|
||||||
|
proc getDimensionsSub*(self: ptr Handle00; dimensionData: var DimensionData00;
|
||||||
|
id: cstring): gboolean {.
|
||||||
|
importc: "rsvg_handle_get_dimensions_sub", libprag.}
|
||||||
|
|
||||||
|
proc dimensionsSub*(self: ptr Handle00; dimensionData: var DimensionData00;
|
||||||
|
id: cstring): gboolean {.
|
||||||
|
importc: "rsvg_handle_get_dimensions_sub", libprag.}
|
||||||
|
|
||||||
|
proc rsvg_handle_get_pixbuf*(self: ptr Handle00): ptr gdkpixbuf.Pixbuf00 {.
|
||||||
|
importc: "rsvg_handle_get_pixbuf", libprag.}
|
||||||
|
|
||||||
|
proc getPixbuf*(self: Handle): gdkpixbuf.Pixbuf =
|
||||||
|
let gobj = rsvg_handle_get_pixbuf(cast[ptr Handle00](self.impl))
|
||||||
|
if g_object_get_qdata(gobj, Quark) != nil:
|
||||||
|
result = cast[gdkpixbuf.Pixbuf](g_object_get_qdata(gobj, Quark))
|
||||||
|
assert(result.impl == gobj)
|
||||||
|
else:
|
||||||
|
new(result, finalizeGObject)
|
||||||
|
result.impl = gobj
|
||||||
|
GC_ref(result)
|
||||||
|
discard g_object_ref_sink(result.impl)
|
||||||
|
g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))
|
||||||
|
g_object_unref(result.impl)
|
||||||
|
assert(g_object_get_qdata(result.impl, Quark) == nil)
|
||||||
|
g_object_set_qdata(result.impl, Quark, addr(result[]))
|
||||||
|
|
||||||
|
proc pixbuf*(self: Handle): gdkpixbuf.Pixbuf =
|
||||||
|
let gobj = rsvg_handle_get_pixbuf(cast[ptr Handle00](self.impl))
|
||||||
|
if g_object_get_qdata(gobj, Quark) != nil:
|
||||||
|
result = cast[gdkpixbuf.Pixbuf](g_object_get_qdata(gobj, Quark))
|
||||||
|
assert(result.impl == gobj)
|
||||||
|
else:
|
||||||
|
new(result, finalizeGObject)
|
||||||
|
result.impl = gobj
|
||||||
|
GC_ref(result)
|
||||||
|
discard g_object_ref_sink(result.impl)
|
||||||
|
g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))
|
||||||
|
g_object_unref(result.impl)
|
||||||
|
assert(g_object_get_qdata(result.impl, Quark) == nil)
|
||||||
|
g_object_set_qdata(result.impl, Quark, addr(result[]))
|
||||||
|
|
||||||
|
proc rsvg_handle_get_pixbuf_sub*(self: ptr Handle00; id: cstring): ptr gdkpixbuf.Pixbuf00 {.
|
||||||
|
importc: "rsvg_handle_get_pixbuf_sub", libprag.}
|
||||||
|
|
||||||
|
proc getPixbufSub*(self: Handle; id: string): gdkpixbuf.Pixbuf =
|
||||||
|
let gobj = rsvg_handle_get_pixbuf_sub(cast[ptr Handle00](self.impl), cstring(id))
|
||||||
|
if g_object_get_qdata(gobj, Quark) != nil:
|
||||||
|
result = cast[gdkpixbuf.Pixbuf](g_object_get_qdata(gobj, Quark))
|
||||||
|
assert(result.impl == gobj)
|
||||||
|
else:
|
||||||
|
new(result, finalizeGObject)
|
||||||
|
result.impl = gobj
|
||||||
|
GC_ref(result)
|
||||||
|
discard g_object_ref_sink(result.impl)
|
||||||
|
g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))
|
||||||
|
g_object_unref(result.impl)
|
||||||
|
assert(g_object_get_qdata(result.impl, Quark) == nil)
|
||||||
|
g_object_set_qdata(result.impl, Quark, addr(result[]))
|
||||||
|
|
||||||
|
proc pixbufSub*(self: Handle; id: string): gdkpixbuf.Pixbuf =
|
||||||
|
let gobj = rsvg_handle_get_pixbuf_sub(cast[ptr Handle00](self.impl), cstring(id))
|
||||||
|
if g_object_get_qdata(gobj, Quark) != nil:
|
||||||
|
result = cast[gdkpixbuf.Pixbuf](g_object_get_qdata(gobj, Quark))
|
||||||
|
assert(result.impl == gobj)
|
||||||
|
else:
|
||||||
|
new(result, finalizeGObject)
|
||||||
|
result.impl = gobj
|
||||||
|
GC_ref(result)
|
||||||
|
discard g_object_ref_sink(result.impl)
|
||||||
|
g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))
|
||||||
|
g_object_unref(result.impl)
|
||||||
|
assert(g_object_get_qdata(result.impl, Quark) == nil)
|
||||||
|
g_object_set_qdata(result.impl, Quark, addr(result[]))
|
||||||
|
|
||||||
|
proc rsvg_handle_has_sub*(self: ptr Handle00; id: cstring): gboolean {.
|
||||||
|
importc: "rsvg_handle_has_sub", libprag.}
|
||||||
|
|
||||||
|
proc hasSub*(self: Handle; id: string): bool =
|
||||||
|
toBool(rsvg_handle_has_sub(cast[ptr Handle00](self.impl), cstring(id)))
|
||||||
|
|
||||||
|
proc rsvg_handle_read_stream_sync*(self: ptr Handle00; stream: ptr gio.InputStream00;
|
||||||
|
cancellable: ptr gio.Cancellable00): gboolean {.
|
||||||
|
importc: "rsvg_handle_read_stream_sync", libprag.}
|
||||||
|
|
||||||
|
proc readStreamSync*(self: Handle; stream: gio.InputStream; cancellable: gio.Cancellable): bool =
|
||||||
|
toBool(rsvg_handle_read_stream_sync(cast[ptr Handle00](self.impl), cast[ptr gio.InputStream00](stream.impl), cast[ptr gio.Cancellable00](cancellable.impl)))
|
||||||
|
|
||||||
|
proc rsvg_handle_render_cairo*(self: ptr Handle00; cr: ptr cairo.Context00): gboolean {.
|
||||||
|
importc: "rsvg_handle_render_cairo", libprag.}
|
||||||
|
|
||||||
|
proc renderCairo*(self: Handle; cr: cairo.Context): bool =
|
||||||
|
toBool(rsvg_handle_render_cairo(cast[ptr Handle00](self.impl), cast[ptr cairo.Context00](cr.impl)))
|
||||||
|
|
||||||
|
proc rsvg_handle_render_cairo_sub*(self: ptr Handle00; cr: ptr cairo.Context00; id: cstring): gboolean {.
|
||||||
|
importc: "rsvg_handle_render_cairo_sub", libprag.}
|
||||||
|
|
||||||
|
proc renderCairoSub*(self: Handle; cr: cairo.Context; id: string): bool =
|
||||||
|
toBool(rsvg_handle_render_cairo_sub(cast[ptr Handle00](self.impl), cast[ptr cairo.Context00](cr.impl), cstring(id)))
|
||||||
|
|
||||||
|
proc rsvg_handle_set_base_gfile*(self: ptr Handle00; baseFile: ptr gio.File00) {.
|
||||||
|
importc: "rsvg_handle_set_base_gfile", libprag.}
|
||||||
|
|
||||||
|
proc setBaseGfile*(self: Handle; baseFile: gio.File) =
|
||||||
|
rsvg_handle_set_base_gfile(cast[ptr Handle00](self.impl), cast[ptr gio.File00](baseFile.impl))
|
||||||
|
|
||||||
|
proc `baseGfile=`*(self: Handle; baseFile: gio.File) =
|
||||||
|
rsvg_handle_set_base_gfile(cast[ptr Handle00](self.impl), cast[ptr gio.File00](baseFile.impl))
|
||||||
|
|
||||||
|
proc rsvg_handle_set_base_uri*(self: ptr Handle00; baseUri: cstring) {.
|
||||||
|
importc: "rsvg_handle_set_base_uri", libprag.}
|
||||||
|
|
||||||
|
proc setBaseUri*(self: Handle; baseUri: string) =
|
||||||
|
rsvg_handle_set_base_uri(cast[ptr Handle00](self.impl), cstring(baseUri))
|
||||||
|
|
||||||
|
proc `baseUri=`*(self: Handle; baseUri: string) =
|
||||||
|
rsvg_handle_set_base_uri(cast[ptr Handle00](self.impl), cstring(baseUri))
|
||||||
|
|
||||||
|
proc rsvg_handle_set_dpi*(self: ptr Handle00; dpi: cdouble) {.
|
||||||
|
importc: "rsvg_handle_set_dpi", libprag.}
|
||||||
|
|
||||||
|
proc setDpi*(self: Handle; dpi: cdouble) =
|
||||||
|
rsvg_handle_set_dpi(cast[ptr Handle00](self.impl), dpi)
|
||||||
|
|
||||||
|
proc `dpi=`*(self: Handle; dpi: cdouble) =
|
||||||
|
rsvg_handle_set_dpi(cast[ptr Handle00](self.impl), dpi)
|
||||||
|
|
||||||
|
proc rsvg_handle_set_dpi_x_y*(self: ptr Handle00; dpiX: cdouble; dpiY: cdouble) {.
|
||||||
|
importc: "rsvg_handle_set_dpi_x_y", libprag.}
|
||||||
|
|
||||||
|
proc setDpiXY*(self: Handle; dpiX: cdouble; dpiY: cdouble) =
|
||||||
|
rsvg_handle_set_dpi_x_y(cast[ptr Handle00](self.impl), dpiX, dpiY)
|
||||||
|
|
||||||
|
proc rsvg_handle_write*(self: ptr Handle00; buf: uint8Array; count: uint64): gboolean {.
|
||||||
|
importc: "rsvg_handle_write", libprag.}
|
||||||
|
|
||||||
|
proc write*(self: Handle; buf: uint8Array; count: uint64): bool =
|
||||||
|
toBool(rsvg_handle_write(cast[ptr Handle00](self.impl), buf, count))
|
||||||
|
|
||||||
|
type
|
||||||
|
HandleFlag* {.size: sizeof(cint), pure.} = enum
|
||||||
|
flagUnlimited = 1
|
||||||
|
flagKeepImageData = 2
|
||||||
|
|
||||||
|
HandleFlags* {.size: sizeof(cint).} = set[HandleFlag]
|
||||||
|
|
||||||
|
proc rsvg_handle_new_from_gfile_sync*(file: ptr gio.File00; flags: HandleFlags; cancellable: ptr gio.Cancellable00): ptr Handle00 {.
|
||||||
|
importc: "rsvg_handle_new_from_gfile_sync", libprag.}
|
||||||
|
|
||||||
|
proc newHandleFromGfileSync*(file: gio.File; flags: HandleFlags; cancellable: gio.Cancellable): Handle =
|
||||||
|
new(result, finalizeGObject)
|
||||||
|
result.impl = rsvg_handle_new_from_gfile_sync(cast[ptr gio.File00](file.impl), flags, cast[ptr gio.Cancellable00](cancellable.impl))
|
||||||
|
GC_ref(result)
|
||||||
|
discard g_object_ref_sink(result.impl)
|
||||||
|
g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))
|
||||||
|
g_object_unref(result.impl)
|
||||||
|
assert(g_object_get_qdata(result.impl, Quark) == nil)
|
||||||
|
g_object_set_qdata(result.impl, Quark, addr(result[]))
|
||||||
|
|
||||||
|
proc initHandleFromGfileSync*[T](result: var T; file: gio.File; flags: HandleFlags; cancellable: gio.Cancellable) =
|
||||||
|
assert(result is Handle)
|
||||||
|
new(result, finalizeGObject)
|
||||||
|
result.impl = rsvg_handle_new_from_gfile_sync(cast[ptr gio.File00](file.impl), flags, cast[ptr gio.Cancellable00](cancellable.impl))
|
||||||
|
GC_ref(result)
|
||||||
|
discard g_object_ref_sink(result.impl)
|
||||||
|
g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))
|
||||||
|
g_object_unref(result.impl)
|
||||||
|
assert(g_object_get_qdata(result.impl, Quark) == nil)
|
||||||
|
g_object_set_qdata(result.impl, Quark, addr(result[]))
|
||||||
|
|
||||||
|
proc rsvg_handle_new_from_stream_sync*(inputStream: ptr gio.InputStream00; baseFile: ptr gio.File00;
|
||||||
|
flags: HandleFlags; cancellable: ptr gio.Cancellable00): ptr Handle00 {.
|
||||||
|
importc: "rsvg_handle_new_from_stream_sync", libprag.}
|
||||||
|
|
||||||
|
proc newHandleFromStreamSync*(inputStream: gio.InputStream; baseFile: gio.File;
|
||||||
|
flags: HandleFlags; cancellable: gio.Cancellable): Handle =
|
||||||
|
new(result, finalizeGObject)
|
||||||
|
result.impl = rsvg_handle_new_from_stream_sync(cast[ptr gio.InputStream00](inputStream.impl), cast[ptr gio.File00](baseFile.impl), flags, cast[ptr gio.Cancellable00](cancellable.impl))
|
||||||
|
GC_ref(result)
|
||||||
|
discard g_object_ref_sink(result.impl)
|
||||||
|
g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))
|
||||||
|
g_object_unref(result.impl)
|
||||||
|
assert(g_object_get_qdata(result.impl, Quark) == nil)
|
||||||
|
g_object_set_qdata(result.impl, Quark, addr(result[]))
|
||||||
|
|
||||||
|
proc initHandleFromStreamSync*[T](result: var T; inputStream: gio.InputStream; baseFile: gio.File;
|
||||||
|
flags: HandleFlags; cancellable: gio.Cancellable) =
|
||||||
|
assert(result is Handle)
|
||||||
|
new(result, finalizeGObject)
|
||||||
|
result.impl = rsvg_handle_new_from_stream_sync(cast[ptr gio.InputStream00](inputStream.impl), cast[ptr gio.File00](baseFile.impl), flags, cast[ptr gio.Cancellable00](cancellable.impl))
|
||||||
|
GC_ref(result)
|
||||||
|
discard g_object_ref_sink(result.impl)
|
||||||
|
g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))
|
||||||
|
g_object_unref(result.impl)
|
||||||
|
assert(g_object_get_qdata(result.impl, Quark) == nil)
|
||||||
|
g_object_set_qdata(result.impl, Quark, addr(result[]))
|
||||||
|
|
||||||
|
proc rsvg_handle_new_with_flags*(flags: HandleFlags): ptr Handle00 {.
|
||||||
|
importc: "rsvg_handle_new_with_flags", libprag.}
|
||||||
|
|
||||||
|
proc newHandleWithFlags*(flags: HandleFlags): Handle =
|
||||||
|
new(result, finalizeGObject)
|
||||||
|
result.impl = rsvg_handle_new_with_flags(flags)
|
||||||
|
GC_ref(result)
|
||||||
|
discard g_object_ref_sink(result.impl)
|
||||||
|
g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))
|
||||||
|
g_object_unref(result.impl)
|
||||||
|
assert(g_object_get_qdata(result.impl, Quark) == nil)
|
||||||
|
g_object_set_qdata(result.impl, Quark, addr(result[]))
|
||||||
|
|
||||||
|
proc initHandleWithFlags*[T](result: var T; flags: HandleFlags) =
|
||||||
|
assert(result is Handle)
|
||||||
|
new(result, finalizeGObject)
|
||||||
|
result.impl = rsvg_handle_new_with_flags(flags)
|
||||||
|
GC_ref(result)
|
||||||
|
discard g_object_ref_sink(result.impl)
|
||||||
|
g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))
|
||||||
|
g_object_unref(result.impl)
|
||||||
|
assert(g_object_get_qdata(result.impl, Quark) == nil)
|
||||||
|
g_object_set_qdata(result.impl, Quark, addr(result[]))
|
||||||
|
|
||||||
|
type
|
||||||
|
PositionData00* {.pure.} = object
|
||||||
|
x*: int32
|
||||||
|
y*: int32
|
||||||
|
PositionData* = ref object
|
||||||
|
impl*: ptr PositionData00
|
||||||
|
|
||||||
|
proc rsvg_handle_get_position_sub*(self: ptr Handle00; positionData: var PositionData00;
|
||||||
|
id: cstring): gboolean {.
|
||||||
|
importc: "rsvg_handle_get_position_sub", libprag.}
|
||||||
|
|
||||||
|
proc getPositionSub*(self: ptr Handle00; positionData: var PositionData00;
|
||||||
|
id: cstring): gboolean {.
|
||||||
|
importc: "rsvg_handle_get_position_sub", libprag.}
|
||||||
|
|
||||||
|
proc positionSub*(self: ptr Handle00; positionData: var PositionData00;
|
||||||
|
id: cstring): gboolean {.
|
||||||
|
importc: "rsvg_handle_get_position_sub", libprag.}
|
||||||
|
|
||||||
|
type
|
||||||
|
HandleClass00* {.pure.} = object
|
||||||
|
parent*: gobject.ObjectClass00
|
||||||
|
abiPadding*: array[15, pointer]
|
||||||
|
HandleClass* = ref object
|
||||||
|
impl*: ptr HandleClass00
|
||||||
|
|
||||||
|
const MAJOR_VERSION* = 2'i32
|
||||||
|
|
||||||
|
const MICRO_VERSION* = 17'i32
|
||||||
|
|
||||||
|
const MINOR_VERSION* = 40'i32
|
||||||
|
|
||||||
|
const VERSION* = "2.40.17"
|
||||||
|
|
||||||
|
proc rsvg_cleanup*() {.
|
||||||
|
importc: "rsvg_cleanup", libprag.}
|
||||||
|
|
||||||
|
proc cleanup*() {.
|
||||||
|
importc: "rsvg_cleanup", libprag.}
|
||||||
|
|
||||||
|
proc rsvg_error_quark*(): uint32 {.
|
||||||
|
importc: "rsvg_error_quark", libprag.}
|
||||||
|
|
||||||
|
proc rsvg_set_default_dpi*(dpi: cdouble) {.
|
||||||
|
importc: "rsvg_set_default_dpi", libprag.}
|
||||||
|
|
||||||
|
proc setDefaultDpi*(dpi: cdouble) {.
|
||||||
|
importc: "rsvg_set_default_dpi", libprag.}
|
||||||
|
|
||||||
|
proc `defaultDpi=`*(dpi: cdouble) {.
|
||||||
|
importc: "rsvg_set_default_dpi", libprag.}
|
||||||
|
|
||||||
|
proc rsvg_set_default_dpi_x_y*(dpiX: cdouble; dpiY: cdouble) {.
|
||||||
|
importc: "rsvg_set_default_dpi_x_y", libprag.}
|
||||||
|
|
||||||
|
proc setDefaultDpiXY*(dpiX: cdouble; dpiY: cdouble) {.
|
||||||
|
importc: "rsvg_set_default_dpi_x_y", libprag.}
|
||||||
|
|
||||||
|
proc `defaultDpiXY=`*(dpiX: cdouble; dpiY: cdouble) {.
|
||||||
|
importc: "rsvg_set_default_dpi_x_y", libprag.}
|
||||||
|
# === remaining symbols:
|
||||||
65
gintro/xlib.nim
Normal file
65
gintro/xlib.nim
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
# dependencies:
|
||||||
|
# immediate dependencies:
|
||||||
|
# libraries:
|
||||||
|
#
|
||||||
|
{.deadCodeElim: on.}
|
||||||
|
|
||||||
|
const Lib* = ""
|
||||||
|
{.pragma: libprag, cdecl, dynlib: Lib.}
|
||||||
|
|
||||||
|
type
|
||||||
|
Display00* {.pure.} = object
|
||||||
|
Display* = ref object
|
||||||
|
impl*: ptr Display00
|
||||||
|
|
||||||
|
type
|
||||||
|
Screen00* {.pure.} = object
|
||||||
|
Screen* = ref object
|
||||||
|
impl*: ptr Screen00
|
||||||
|
|
||||||
|
type
|
||||||
|
Visual00* {.pure.} = object
|
||||||
|
Visual* = ref object
|
||||||
|
impl*: ptr Visual00
|
||||||
|
|
||||||
|
type
|
||||||
|
XEvent00* = object {.union.}
|
||||||
|
XEvent* = ref object
|
||||||
|
impl*: ptr XEvent00
|
||||||
|
|
||||||
|
type
|
||||||
|
XConfigureEvent00* {.pure.} = object
|
||||||
|
XConfigureEvent* = ref object
|
||||||
|
impl*: ptr XConfigureEvent00
|
||||||
|
|
||||||
|
type
|
||||||
|
XImage00* {.pure.} = object
|
||||||
|
XImage* = ref object
|
||||||
|
impl*: ptr XImage00
|
||||||
|
|
||||||
|
type
|
||||||
|
XFontStruct00* {.pure.} = object
|
||||||
|
XFontStruct* = ref object
|
||||||
|
impl*: ptr XFontStruct00
|
||||||
|
|
||||||
|
type
|
||||||
|
XTrapezoid00* {.pure.} = object
|
||||||
|
XTrapezoid* = ref object
|
||||||
|
impl*: ptr XTrapezoid00
|
||||||
|
|
||||||
|
type
|
||||||
|
XVisualInfo00* {.pure.} = object
|
||||||
|
XVisualInfo* = ref object
|
||||||
|
impl*: ptr XVisualInfo00
|
||||||
|
|
||||||
|
type
|
||||||
|
XWindowAttributes00* {.pure.} = object
|
||||||
|
XWindowAttributes* = ref object
|
||||||
|
impl*: ptr XWindowAttributes00
|
||||||
|
|
||||||
|
proc XOpenDisplay*() {.
|
||||||
|
importc: "XOpenDisplay", libprag.}
|
||||||
|
|
||||||
|
proc openDisplay*() {.
|
||||||
|
importc: "XOpenDisplay", libprag.}
|
||||||
|
# === remaining symbols:
|
||||||
181
tests/combinatorics.nim
Normal file
181
tests/combinatorics.nim
Normal file
|
|
@ -0,0 +1,181 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod Combinatorics Module
|
||||||
|
# (c) Copyright 2014 Reimer Behrends
|
||||||
|
#
|
||||||
|
# See the file "LICENSE", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
## The combinatorics module contains routines to enumerate permutations,
|
||||||
|
## choices, or combinations of a sequence or array. These routines are
|
||||||
|
## implemented as iterators that yield sequences. ``sequtils.toSeq``
|
||||||
|
## can be used to gather all results in a single sequence.
|
||||||
|
##
|
||||||
|
## The implementations assume that the input does not contain duplicates;
|
||||||
|
## if it contains duplicate entries, these will be treated as distinct
|
||||||
|
## items.
|
||||||
|
|
||||||
|
iterator permutations*[T](s: openarray[T]): seq[T] =
|
||||||
|
## Enumerates all possible permutations of `s`. Example:
|
||||||
|
##
|
||||||
|
## .. code-block:: nimrod
|
||||||
|
## for p in permutations(@[1,2,3]):
|
||||||
|
##
|
||||||
|
## ...generates this output:
|
||||||
|
##
|
||||||
|
## .. code-block::
|
||||||
|
## @[1, 2, 3]
|
||||||
|
## @[2, 1, 3]
|
||||||
|
## @[1, 3, 2]
|
||||||
|
## @[2, 3, 1]
|
||||||
|
## @[3, 2, 1]
|
||||||
|
## @[3, 1, 2]
|
||||||
|
let n = len(s)
|
||||||
|
var pos = newSeq[int](n)
|
||||||
|
var current = newSeq[T](n)
|
||||||
|
for i in 0..n-1:
|
||||||
|
pos[i] = i
|
||||||
|
while true:
|
||||||
|
for i in 0..n-1:
|
||||||
|
current[i] = current[pos[i]]
|
||||||
|
current[pos[i]] = s[i]
|
||||||
|
yield current
|
||||||
|
var i = 1
|
||||||
|
while i < n:
|
||||||
|
pos[i] -= 1
|
||||||
|
if pos[i] < 0:
|
||||||
|
pos[i] = i
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
if i >= n:
|
||||||
|
break
|
||||||
|
|
||||||
|
iterator combinations*[T](s: openarray[T], k: int): seq[T] =
|
||||||
|
## Enumerates all combinations of `k` distinct elements
|
||||||
|
## out of `s`. Example:
|
||||||
|
##
|
||||||
|
## .. code-block:: nimrod
|
||||||
|
## for p in combinations(@[1,2,3], 2):
|
||||||
|
##
|
||||||
|
## ...generates this output:
|
||||||
|
##
|
||||||
|
## .. code-block::
|
||||||
|
## @[1, 2]
|
||||||
|
## @[1, 3]
|
||||||
|
## @[2, 3]
|
||||||
|
let n = len(s)
|
||||||
|
assert k >= 0 and k <= n
|
||||||
|
var pos = newSeq[int](k)
|
||||||
|
var current = newSeq[T](k)
|
||||||
|
for i in 0..k-1:
|
||||||
|
pos[k-i-1] = i
|
||||||
|
var done = false
|
||||||
|
while not done:
|
||||||
|
for i in 0..k-1:
|
||||||
|
current[i] = s[pos[k-i-1]]
|
||||||
|
yield current
|
||||||
|
var i = 0
|
||||||
|
while i < k:
|
||||||
|
pos[i] += 1
|
||||||
|
if pos[i] < n-i:
|
||||||
|
for j in 0..i-1:
|
||||||
|
pos[j] = pos[i] + i - j
|
||||||
|
break
|
||||||
|
i += 1
|
||||||
|
if i >= k:
|
||||||
|
break
|
||||||
|
|
||||||
|
iterator multicombinations*[T](s: openarray[T], k: int): seq[T] =
|
||||||
|
## Enumerates all ordered combinations of `k` elements
|
||||||
|
## out of `s` where the elements can be repeated.
|
||||||
|
## Example:
|
||||||
|
##
|
||||||
|
## .. code-block:: nimrod
|
||||||
|
## for p in multicombinations(@[1,2,3], 2):
|
||||||
|
##
|
||||||
|
## ...generates this output:
|
||||||
|
##
|
||||||
|
## .. code-block::
|
||||||
|
## @[1, 1]
|
||||||
|
## @[1, 2]
|
||||||
|
## @[1, 3]
|
||||||
|
## @[2, 2]
|
||||||
|
## @[2, 3]
|
||||||
|
## @[3, 3]
|
||||||
|
let n = len(s)
|
||||||
|
assert k >= 0 and k <= n
|
||||||
|
var pos = newSeq[int](k)
|
||||||
|
var current = newSeq[T](k)
|
||||||
|
var done = false
|
||||||
|
while not done:
|
||||||
|
for i in 0..k-1:
|
||||||
|
current[i] = s[pos[k-i-1]]
|
||||||
|
yield current
|
||||||
|
var i = 0
|
||||||
|
while i < k:
|
||||||
|
pos[i] += 1
|
||||||
|
if pos[i] < n:
|
||||||
|
for j in 0..i-1:
|
||||||
|
pos[j] = pos[i]
|
||||||
|
break
|
||||||
|
i += 1
|
||||||
|
if i == k:
|
||||||
|
break
|
||||||
|
|
||||||
|
iterator tuples*[T](s: openarray[T], k: int): seq[T] =
|
||||||
|
## Enumerates all ordered combinations of `k` elements
|
||||||
|
## out of `s` where the elements can be repeated. This is
|
||||||
|
## essentially the Cartesian product of `s` with itself
|
||||||
|
## for `k` factors. Example:
|
||||||
|
##
|
||||||
|
## .. code-block:: nimrod
|
||||||
|
## for p in tuples(@[1,2], 2):
|
||||||
|
##
|
||||||
|
## ...generates this output:
|
||||||
|
##
|
||||||
|
## .. code-block::
|
||||||
|
## @[1, 1]
|
||||||
|
## @[1, 2]
|
||||||
|
## @[2, 1]
|
||||||
|
## @[2, 2]
|
||||||
|
if k >= 0 and len(s) > 0:
|
||||||
|
var pos = newSeq[int](k)
|
||||||
|
var current = newSeq[T](k)
|
||||||
|
while true:
|
||||||
|
for i in 0..k-1:
|
||||||
|
current[i] = s[pos[i]]
|
||||||
|
yield current
|
||||||
|
var i = 0
|
||||||
|
while i < k:
|
||||||
|
pos[i] += 1
|
||||||
|
if pos[i] >= len(s):
|
||||||
|
pos[i] = 0
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
if i == k:
|
||||||
|
break
|
||||||
|
|
||||||
|
when isMainModule:
|
||||||
|
import sets, math, sequtils
|
||||||
|
template count(s: untyped): untyped =
|
||||||
|
block:
|
||||||
|
var i = 0
|
||||||
|
for x in s: i += 1
|
||||||
|
i
|
||||||
|
proc mcoeff(a, b: int): int =
|
||||||
|
binom(a+b-1, b)
|
||||||
|
doAssert count(permutations[int]([])) == 1
|
||||||
|
doAssert count(permutations([1,2,3,4,5])) == fac(5)
|
||||||
|
doAssert count(permutations(["a", "b", "c"])) == fac(3)
|
||||||
|
doAssert count(combinations([1,2,3,4], 1)) == binom(4, 1)
|
||||||
|
doAssert count(combinations([1,2,3,4], 2)) == binom(4, 2)
|
||||||
|
doAssert count(combinations([1,2,3,4], 3)) == binom(4, 3)
|
||||||
|
doAssert count(combinations(["a", "b", "c", "d", "e"], 3)) == 10
|
||||||
|
doAssert count(multicombinations([1,2,3,4], 1)) == mcoeff(4, 1)
|
||||||
|
doAssert count(multicombinations([1,2,3,4], 2)) == mcoeff(4, 2)
|
||||||
|
doAssert count(multicombinations([1,2,3,4], 3)) == mcoeff(4, 3)
|
||||||
|
doAssert count(tuples([1,2,3,4], 3)) == 4*4*4
|
||||||
|
doAssert count(tuples([1,2], 10)) == 1024
|
||||||
1221
tests/gen.nim
Normal file
1221
tests/gen.nim
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue