High level GObject-Introspection based GTK3/GTK4 bindings for Nim language
| examples | ||
| gintro | ||
| tests | ||
| gintro.nimble | ||
| LICENSE | ||
| README.adoc | ||
| README.html | ||
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 1.5.8">
<meta name="author" content="(c) Stefan Salewski">
<title>High level GTK3 (and GTK4) bindings for the Nim programming language</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700">
<style>
/* Asciidoctor default stylesheet | MIT License | http://asciidoctor.org */
/* Uncomment @import statement below to use as custom stylesheet */
/*@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700";*/
article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}
audio,canvas,video{display:inline-block}
audio:not([controls]){display:none;height:0}
script{display:none!important}
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}
a{background:transparent}
a:focus{outline:thin dotted}
a:active,a:hover{outline:0}
h1{font-size:2em;margin:.67em 0}
abbr[title]{border-bottom:1px dotted}
b,strong{font-weight:bold}
dfn{font-style:italic}
hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}
mark{background:#ff0;color:#000}
code,kbd,pre,samp{font-family:monospace;font-size:1em}
pre{white-space:pre-wrap}
q{quotes:"\201C" "\201D" "\2018" "\2019"}
small{font-size:80%}
sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
sup{top:-.5em}
sub{bottom:-.25em}
img{border:0}
svg:not(:root){overflow:hidden}
figure{margin:0}
fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}
legend{border:0;padding:0}
button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}
button,input{line-height:normal}
button,select{text-transform:none}
button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}
button[disabled],html input[disabled]{cursor:default}
input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
textarea{overflow:auto;vertical-align:top}
table{border-collapse:collapse;border-spacing:0}
*,*::before,*::after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
html,body{font-size:100%}
body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto;tab-size:4;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
a:hover{cursor:pointer}
img,object,embed{max-width:100%;height:auto}
object,embed{height:100%}
img{-ms-interpolation-mode:bicubic}
.left{float:left!important}
.right{float:right!important}
.text-left{text-align:left!important}
.text-right{text-align:right!important}
.text-center{text-align:center!important}
.text-justify{text-align:justify!important}
.hide{display:none}
img,object,svg{display:inline-block;vertical-align:middle}
textarea{height:auto;min-height:50px}
select{width:100%}
.center{margin-left:auto;margin-right:auto}
.stretch{width:100%}
.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}
div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0;direction:ltr}
a{color:#2156a5;text-decoration:underline;line-height:inherit}
a:hover,a:focus{color:#1d4b8f}
a img{border:none}
p{font-family:inherit;font-weight:400;font-size:1em;line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}
p aside{font-size:.875em;line-height:1.35;font-style:italic}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}
h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}
h1{font-size:2.125em}
h2{font-size:1.6875em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}
h4,h5{font-size:1.125em}
h6{font-size:1em}
hr{border:solid #dddddf;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0}
em,i{font-style:italic;line-height:inherit}
strong,b{font-weight:bold;line-height:inherit}
small{font-size:60%;line-height:inherit}
code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)}
ul,ol,dl{font-size:1em;line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}
ul,ol{margin-left:1.5em}
ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em}
ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}
ul.square{list-style-type:square}
ul.circle{list-style-type:circle}
ul.disc{list-style-type:disc}
ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}
dl dt{margin-bottom:.3125em;font-weight:bold}
dl dd{margin-bottom:1.25em}
abbr,acronym{text-transform:uppercase;font-size:90%;color:rgba(0,0,0,.8);border-bottom:1px dotted #ddd;cursor:help}
abbr{text-transform:none}
blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}
blockquote cite{display:block;font-size:.9375em;color:rgba(0,0,0,.6)}
blockquote cite::before{content:"\2014 \0020"}
blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,.6)}
blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}
@media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}
h1{font-size:2.75em}
h2{font-size:2.3125em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}
h4{font-size:1.4375em}}
table{background:#fff;margin-bottom:1.25em;border:solid 1px #dedede}
table thead,table tfoot{background:#f7f8f7}
table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}
table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
table tr.even,table tr.alt,table tr:nth-of-type(even){background:#f8f8f7}
table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{display:table-cell;line-height:1.6}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}
h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
.clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table}
.clearfix::after,.float-group::after{clear:both}
*:not(pre)>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background-color:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed;word-wrap:break-word}
*:not(pre)>code.nobreak{word-wrap:normal}
*:not(pre)>code.nowrap{white-space:nowrap}
pre,pre>code{line-height:1.45;color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;text-rendering:optimizeSpeed}
em em{font-style:normal}
strong strong{font-weight:400}
.keyseq{color:rgba(51,51,51,.8)}
kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background-color:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
.keyseq kbd:first-child{margin-left:0}
.keyseq kbd:last-child{margin-right:0}
.menuseq,.menuref{color:#000}
.menuseq b:not(.caret),.menuref{font-weight:inherit}
.menuseq{word-spacing:-.02em}
.menuseq b.caret{font-size:1.25em;line-height:.8}
.menuseq i.caret{font-weight:bold;text-align:center;width:.45em}
b.button::before,b.button::after{position:relative;top:-1px;font-weight:400}
b.button::before{content:"[";padding:0 3px 0 2px}
b.button::after{content:"]";padding:0 2px 0 3px}
p a>code:hover{color:rgba(0,0,0,.9)}
#header,#content,#footnotes,#footer{width:100%;margin-left:auto;margin-right:auto;margin-top:0;margin-bottom:0;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}
#header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table}
#header::after,#content::after,#footnotes::after,#footer::after{clear:both}
#content{margin-top:1.25em}
#content::before{content:none}
#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}
#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf}
#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px}
#header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap}
#header .details span:first-child{margin-left:-.125em}
#header .details span.email a{color:rgba(0,0,0,.85)}
#header .details br{display:none}
#header .details br+span::before{content:"\00a0\2013\00a0"}
#header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)}
#header .details br+span#revremark::before{content:"\00a0|\00a0"}
#header #revnumber{text-transform:capitalize}
#header #revnumber::after{content:"\00a0"}
#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #dddddf;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}
#toc{border-bottom:1px solid #e7e7e9;padding-bottom:.5em}
#toc>ul{margin-left:.125em}
#toc ul.sectlevel0>li>a{font-style:italic}
#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}
#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none}
#toc li{line-height:1.3334;margin-top:.3334em}
#toc a{text-decoration:none}
#toc a:active{text-decoration:underline}
#toctitle{color:#7a2518;font-size:1.2em}
@media screen and (min-width:768px){#toctitle{font-size:1.375em}
body.toc2{padding-left:15em;padding-right:0}
#toc.toc2{margin-top:0!important;background-color:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
#toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}
#toc.toc2>ul{font-size:.9em;margin-bottom:0}
#toc.toc2 ul ul{margin-left:0;padding-left:1em}
#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}
body.toc2.toc-right{padding-left:0;padding-right:15em}
body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #e7e7e9;left:auto;right:0}}
@media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}
#toc.toc2{width:20em}
#toc.toc2 #toctitle{font-size:1.375em}
#toc.toc2>ul{font-size:.95em}
#toc.toc2 ul ul{padding-left:1.25em}
body.toc2.toc-right{padding-left:0;padding-right:20em}}
#content #toc{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
#content #toc>:first-child{margin-top:0}
#content #toc>:last-child{margin-bottom:0}
#footer{max-width:100%;background-color:rgba(0,0,0,.8);padding:1.25em}
#footer-text{color:rgba(255,255,255,.8);line-height:1.44}
#content{margin-bottom:.625em}
.sect1{padding-bottom:.625em}
@media screen and (min-width:768px){#content{margin-bottom:1.25em}
.sect1{padding-bottom:1.25em}}
.sect1:last-child{padding-bottom:0}
.sect1+.sect1{border-top:1px solid #e7e7e9}
#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}
#content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em}
#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}
#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}
#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}
.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}
.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic}
table.tableblock.fit-content>caption.title{white-space:nowrap;width:0}
.paragraph.lead>p,#preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)}
table.tableblock #preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:inherit}
.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}
.admonitionblock>table td.icon{text-align:center;width:80px}
.admonitionblock>table td.icon img{max-width:none}
.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase}
.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #dddddf;color:rgba(0,0,0,.6)}
.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}
.exampleblock>.content{border-style:solid;border-width:1px;border-color:#e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;-webkit-border-radius:4px;border-radius:4px}
.exampleblock>.content>:first-child{margin-top:0}
.exampleblock>.content>:last-child{margin-bottom:0}
.sidebarblock{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
.sidebarblock>:first-child{margin-top:0}
.sidebarblock>:last-child{margin-bottom:0}
.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}
.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}
.literalblock pre,.listingblock pre:not(.highlight),.listingblock pre[class="highlight"],.listingblock pre[class^="highlight "],.listingblock pre.CodeRay,.listingblock pre.prettyprint{background:#f7f7f8}
.sidebarblock .literalblock pre,.sidebarblock .listingblock pre:not(.highlight),.sidebarblock .listingblock pre[class="highlight"],.sidebarblock .listingblock pre[class^="highlight "],.sidebarblock .listingblock pre.CodeRay,.sidebarblock .listingblock pre.prettyprint{background:#f2f1f1}
.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{-webkit-border-radius:4px;border-radius:4px;word-wrap:break-word;overflow-x:auto;padding:1em;font-size:.8125em}
@media screen and (min-width:768px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:.90625em}}
@media screen and (min-width:1280px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:1em}}
.literalblock pre.nowrap,.literalblock pre.nowrap pre,.listingblock pre.nowrap,.listingblock pre.nowrap pre{white-space:pre;word-wrap:normal}
.literalblock.output pre{color:#f7f7f8;background-color:rgba(0,0,0,.9)}
.listingblock pre.highlightjs{padding:0}
.listingblock pre.highlightjs>code{padding:1em;-webkit-border-radius:4px;border-radius:4px}
.listingblock pre.prettyprint{border-width:0}
.listingblock>.content{position:relative}
.listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:#999}
.listingblock:hover code[data-lang]::before{display:block}
.listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:#999}
.listingblock.terminal pre .command:not([data-prompt])::before{content:"$"}
table.pyhltable{border-collapse:separate;border:0;margin-bottom:0;background:none}
table.pyhltable td{vertical-align:top;padding-top:0;padding-bottom:0;line-height:1.45}
table.pyhltable td.code{padding-left:.75em;padding-right:0}
pre.pygments .lineno,table.pyhltable td:not(.code){color:#999;padding-left:0;padding-right:.5em;border-right:1px solid #dddddf}
pre.pygments .lineno{display:inline-block;margin-right:.25em}
table.pyhltable .linenodiv{background:none!important;padding-right:0!important}
.quoteblock{margin:0 1em 1.25em 1.5em;display:table}
.quoteblock>.title{margin-left:-1.5em;margin-bottom:.75em}
.quoteblock blockquote,.quoteblock p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}
.quoteblock blockquote{margin:0;padding:0;border:0}
.quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}
.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}
.quoteblock .attribution{margin-top:.75em;margin-right:.5ex;text-align:right}
.verseblock{margin:0 1em 1.25em}
.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}
.verseblock pre strong{font-weight:400}
.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}
.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}
.quoteblock .attribution br,.verseblock .attribution br{display:none}
.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)}
.quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none}
.quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:1.6;word-spacing:0}
.quoteblock.abstract{margin:0 1em 1.25em;display:block}
.quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center}
.quoteblock.excerpt,.quoteblock .quoteblock{margin:0 0 1.25em;padding:0 0 .25em 1em;border-left:.25em solid #dddddf}
.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:1.0625rem}
.quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;text-align:left;margin-right:0}
table.tableblock{max-width:100%;border-collapse:separate}
p.tableblock:last-child{margin-bottom:0}
td.tableblock>.content{margin-bottom:-1.25em}
table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}
table.grid-all>thead>tr>.tableblock,table.grid-all>tbody>tr>.tableblock{border-width:0 1px 1px 0}
table.grid-all>tfoot>tr>.tableblock{border-width:1px 1px 0 0}
table.grid-cols>*>tr>.tableblock{border-width:0 1px 0 0}
table.grid-rows>thead>tr>.tableblock,table.grid-rows>tbody>tr>.tableblock{border-width:0 0 1px}
table.grid-rows>tfoot>tr>.tableblock{border-width:1px 0 0}
table.grid-all>*>tr>.tableblock:last-child,table.grid-cols>*>tr>.tableblock:last-child{border-right-width:0}
table.grid-all>tbody>tr:last-child>.tableblock,table.grid-all>thead:last-child>tr>.tableblock,table.grid-rows>tbody>tr:last-child>.tableblock,table.grid-rows>thead:last-child>tr>.tableblock{border-bottom-width:0}
table.frame-all{border-width:1px}
table.frame-sides{border-width:0 1px}
table.frame-topbot,table.frame-ends{border-width:1px 0}
table.stripes-all tr,table.stripes-odd tr:nth-of-type(odd){background:#f8f8f7}
table.stripes-none tr,table.stripes-odd tr:nth-of-type(even){background:none}
th.halign-left,td.halign-left{text-align:left}
th.halign-right,td.halign-right{text-align:right}
th.halign-center,td.halign-center{text-align:center}
th.valign-top,td.valign-top{vertical-align:top}
th.valign-bottom,td.valign-bottom{vertical-align:bottom}
th.valign-middle,td.valign-middle{vertical-align:middle}
table thead th,table tfoot th{font-weight:bold}
tbody tr th{display:table-cell;line-height:1.6;background:#f7f8f7}
tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}
p.tableblock>code:only-child{background:none;padding:0}
p.tableblock{font-size:1em}
td>div.verse{white-space:pre}
ol{margin-left:1.75em}
ul li ol{margin-left:1.5em}
dl dd{margin-left:1.125em}
dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}
ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}
ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none}
ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em}
ul.unstyled,ol.unstyled{margin-left:0}
ul.checklist{margin-left:.625em}
ul.checklist li>p:first-child>.fa-square-o:first-child,ul.checklist li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em}
ul.checklist li>p:first-child>input[type="checkbox"]:first-child{margin-right:.25em}
ul.inline{display:-ms-flexbox;display:-webkit-box;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em}
ul.inline>li{margin-left:1.25em}
.unstyled dl dt{font-weight:400;font-style:normal}
ol.arabic{list-style-type:decimal}
ol.decimal{list-style-type:decimal-leading-zero}
ol.loweralpha{list-style-type:lower-alpha}
ol.upperalpha{list-style-type:upper-alpha}
ol.lowerroman{list-style-type:lower-roman}
ol.upperroman{list-style-type:upper-roman}
ol.lowergreek{list-style-type:lower-greek}
.hdlist>table,.colist>table{border:0;background:none}
.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}
td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em}
td.hdlist1{font-weight:bold;padding-bottom:1.25em}
.literalblock+.colist,.listingblock+.colist{margin-top:-.5em}
.colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top}
.colist td:not([class]):first-child img{max-width:none}
.colist td:not([class]):last-child{padding:.25em 0}
.thumb,.th{line-height:0;display:inline-block;border:solid 4px #fff;-webkit-box-shadow:0 0 0 1px #ddd;box-shadow:0 0 0 1px #ddd}
.imageblock.left{margin:.25em .625em 1.25em 0}
.imageblock.right{margin:.25em 0 1.25em .625em}
.imageblock>.title{margin-bottom:0}
.imageblock.thumb,.imageblock.th{border-width:6px}
.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}
.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}
.image.left{margin-right:.625em}
.image.right{margin-left:.625em}
a.image{text-decoration:none;display:inline-block}
a.image object{pointer-events:none}
sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super}
sup.footnote a,sup.footnoteref a{text-decoration:none}
sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}
#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0}
#footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em}
#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em}
#footnotes .footnote:last-of-type{margin-bottom:0}
#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}
.gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0}
.gist .file-data>table td.line-data{width:99%}
div.unbreakable{page-break-inside:avoid}
.big{font-size:larger}
.small{font-size:smaller}
.underline{text-decoration:underline}
.overline{text-decoration:overline}
.line-through{text-decoration:line-through}
.aqua{color:#00bfbf}
.aqua-background{background-color:#00fafa}
.black{color:#000}
.black-background{background-color:#000}
.blue{color:#0000bf}
.blue-background{background-color:#0000fa}
.fuchsia{color:#bf00bf}
.fuchsia-background{background-color:#fa00fa}
.gray{color:#606060}
.gray-background{background-color:#7d7d7d}
.green{color:#006000}
.green-background{background-color:#007d00}
.lime{color:#00bf00}
.lime-background{background-color:#00fa00}
.maroon{color:#600000}
.maroon-background{background-color:#7d0000}
.navy{color:#000060}
.navy-background{background-color:#00007d}
.olive{color:#606000}
.olive-background{background-color:#7d7d00}
.purple{color:#600060}
.purple-background{background-color:#7d007d}
.red{color:#bf0000}
.red-background{background-color:#fa0000}
.silver{color:#909090}
.silver-background{background-color:#bcbcbc}
.teal{color:#006060}
.teal-background{background-color:#007d7d}
.white{color:#bfbfbf}
.white-background{background-color:#fafafa}
.yellow{color:#bfbf00}
.yellow-background{background-color:#fafa00}
span.icon>.fa{cursor:default}
a span.icon>.fa{cursor:inherit}
.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
.admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c}
.admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
.admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900}
.admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400}
.admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000}
.conum[data-value]{display:inline-block;color:#fff!important;background-color:rgba(0,0,0,.8);-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
.conum[data-value] *{color:#fff!important}
.conum[data-value]+b{display:none}
.conum[data-value]::after{content:attr(data-value)}
pre .conum[data-value]{position:relative;top:-.125em}
b.conum *{color:inherit!important}
.conum:not([data-value]):empty{display:none}
dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}
h1,h2,p,td.content,span.alt{letter-spacing:-.01em}
p strong,td.content strong,div.footnote strong{letter-spacing:-.005em}
p,blockquote,dt,td.content,span.alt{font-size:1.0625rem}
p{margin-bottom:1.25rem}
.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}
.exampleblock>.content{background-color:#fffef7;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc}
.print-only{display:none!important}
@page{margin:1.25cm .75cm}
@media print{*{-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important}
html{font-size:80%}
a{color:inherit!important;text-decoration:underline!important}
a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important}
a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em}
abbr[title]::after{content:" (" attr(title) ")"}
pre,blockquote,tr,img,object,svg{page-break-inside:avoid}
thead{display:table-header-group}
svg{max-width:100%}
p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3}
h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid}
#toc,.sidebarblock,.exampleblock>.content{background:none!important}
#toc{border-bottom:1px solid #dddddf!important;padding-bottom:0!important}
body.book #header{text-align:center}
body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em}
body.book #header .details{border:0!important;display:block;padding:0!important}
body.book #header .details span:first-child{margin-left:0!important}
body.book #header .details br{display:block}
body.book #header .details br+span::before{content:none!important}
body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}
body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}
.listingblock code[data-lang]::before{display:block}
#footer{padding:0 .9375em}
.hide-on-print{display:none!important}
.print-only{display:block!important}
.hide-for-print{display:none!important}
.show-for-print{display:inherit!important}}
@media print,amzn-kf8{#header>h1:first-child{margin-top:1.25rem}
.sect1{padding:0!important}
.sect1+.sect1{border:0}
#footer{background:none}
#footer-text{color:rgba(0,0,0,.6);font-size:.9em}}
@media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}}
</style>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<style>
.listingblock .pygments .hll { background-color: #49483e }
.listingblock .pygments, .listingblock .pygments code { background: #272822; color: #f8f8f2 }
.listingblock .pygments .tok-c { color: #75715e } /* Comment */
.listingblock .pygments .tok-err { color: #960050; background-color: #1e0010 } /* Error */
.listingblock .pygments .tok-k { color: #66d9ef } /* Keyword */
.listingblock .pygments .tok-l { color: #ae81ff } /* Literal */
.listingblock .pygments .tok-n { color: #f8f8f2 } /* Name */
.listingblock .pygments .tok-o { color: #f92672 } /* Operator */
.listingblock .pygments .tok-p { color: #f8f8f2 } /* Punctuation */
.listingblock .pygments .tok-ch { color: #75715e } /* Comment.Hashbang */
.listingblock .pygments .tok-cm { color: #75715e } /* Comment.Multiline */
.listingblock .pygments .tok-cp { color: #75715e } /* Comment.Preproc */
.listingblock .pygments .tok-cpf { color: #75715e } /* Comment.PreprocFile */
.listingblock .pygments .tok-c1 { color: #75715e } /* Comment.Single */
.listingblock .pygments .tok-cs { color: #75715e } /* Comment.Special */
.listingblock .pygments .tok-gd { color: #f92672 } /* Generic.Deleted */
.listingblock .pygments .tok-ge { font-style: italic } /* Generic.Emph */
.listingblock .pygments .tok-gi { color: #a6e22e } /* Generic.Inserted */
.listingblock .pygments .tok-gs { font-weight: bold } /* Generic.Strong */
.listingblock .pygments .tok-gu { color: #75715e } /* Generic.Subheading */
.listingblock .pygments .tok-kc { color: #66d9ef } /* Keyword.Constant */
.listingblock .pygments .tok-kd { color: #66d9ef } /* Keyword.Declaration */
.listingblock .pygments .tok-kn { color: #f92672 } /* Keyword.Namespace */
.listingblock .pygments .tok-kp { color: #66d9ef } /* Keyword.Pseudo */
.listingblock .pygments .tok-kr { color: #66d9ef } /* Keyword.Reserved */
.listingblock .pygments .tok-kt { color: #66d9ef } /* Keyword.Type */
.listingblock .pygments .tok-ld { color: #e6db74 } /* Literal.Date */
.listingblock .pygments .tok-m { color: #ae81ff } /* Literal.Number */
.listingblock .pygments .tok-s { color: #e6db74 } /* Literal.String */
.listingblock .pygments .tok-na { color: #a6e22e } /* Name.Attribute */
.listingblock .pygments .tok-nb { color: #f8f8f2 } /* Name.Builtin */
.listingblock .pygments .tok-nc { color: #a6e22e } /* Name.Class */
.listingblock .pygments .tok-no { color: #66d9ef } /* Name.Constant */
.listingblock .pygments .tok-nd { color: #a6e22e } /* Name.Decorator */
.listingblock .pygments .tok-ni { color: #f8f8f2 } /* Name.Entity */
.listingblock .pygments .tok-ne { color: #a6e22e } /* Name.Exception */
.listingblock .pygments .tok-nf { color: #a6e22e } /* Name.Function */
.listingblock .pygments .tok-nl { color: #f8f8f2 } /* Name.Label */
.listingblock .pygments .tok-nn { color: #f8f8f2 } /* Name.Namespace */
.listingblock .pygments .tok-nx { color: #a6e22e } /* Name.Other */
.listingblock .pygments .tok-py { color: #f8f8f2 } /* Name.Property */
.listingblock .pygments .tok-nt { color: #f92672 } /* Name.Tag */
.listingblock .pygments .tok-nv { color: #f8f8f2 } /* Name.Variable */
.listingblock .pygments .tok-ow { color: #f92672 } /* Operator.Word */
.listingblock .pygments .tok-w { color: #f8f8f2 } /* Text.Whitespace */
.listingblock .pygments .tok-mb { color: #ae81ff } /* Literal.Number.Bin */
.listingblock .pygments .tok-mf { color: #ae81ff } /* Literal.Number.Float */
.listingblock .pygments .tok-mh { color: #ae81ff } /* Literal.Number.Hex */
.listingblock .pygments .tok-mi { color: #ae81ff } /* Literal.Number.Integer */
.listingblock .pygments .tok-mo { color: #ae81ff } /* Literal.Number.Oct */
.listingblock .pygments .tok-sa { color: #e6db74 } /* Literal.String.Affix */
.listingblock .pygments .tok-sb { color: #e6db74 } /* Literal.String.Backtick */
.listingblock .pygments .tok-sc { color: #e6db74 } /* Literal.String.Char */
.listingblock .pygments .tok-dl { color: #e6db74 } /* Literal.String.Delimiter */
.listingblock .pygments .tok-sd { color: #e6db74 } /* Literal.String.Doc */
.listingblock .pygments .tok-s2 { color: #e6db74 } /* Literal.String.Double */
.listingblock .pygments .tok-se { color: #ae81ff } /* Literal.String.Escape */
.listingblock .pygments .tok-sh { color: #e6db74 } /* Literal.String.Heredoc */
.listingblock .pygments .tok-si { color: #e6db74 } /* Literal.String.Interpol */
.listingblock .pygments .tok-sx { color: #e6db74 } /* Literal.String.Other */
.listingblock .pygments .tok-sr { color: #e6db74 } /* Literal.String.Regex */
.listingblock .pygments .tok-s1 { color: #e6db74 } /* Literal.String.Single */
.listingblock .pygments .tok-ss { color: #e6db74 } /* Literal.String.Symbol */
.listingblock .pygments .tok-bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.listingblock .pygments .tok-fm { color: #a6e22e } /* Name.Function.Magic */
.listingblock .pygments .tok-vc { color: #f8f8f2 } /* Name.Variable.Class */
.listingblock .pygments .tok-vg { color: #f8f8f2 } /* Name.Variable.Global */
.listingblock .pygments .tok-vi { color: #f8f8f2 } /* Name.Variable.Instance */
.listingblock .pygments .tok-vm { color: #f8f8f2 } /* Name.Variable.Magic */
.listingblock .pygments .tok-il { color: #ae81ff } /* Literal.Number.Integer.Long */
</style>
</head>
<body class="article toc2 toc-left">
<div id="header">
<h1>High level GTK3 (and GTK4) bindings for the Nim programming language</h1>
<div class="details">
<span id="author" class="author">(c) Stefan Salewski</span><br>
</div>
<div id="toc" class="toc2">
<div id="toctitle">Table of Contents</div>
<ul class="sectlevel1">
<li><a href="#_current_state_of_these_bindings">Current state of these bindings</a></li>
<li><a href="#_how_to_try_it_out">How to try it out</a></li>
<li><a href="#_a_few_basic_examples">A few basic examples</a></li>
<li><a href="#_optional_type_safe_parameters_for_callbacks">Optional, type safe parameters for callbacks</a></li>
<li><a href="#_extending_or_sub_classing_widgets">Extending or sub-classing Widgets</a></li>
<li><a href="#_css_styles_gerrors_and_exceptions">CSS styles, GErrors and Exceptions</a></li>
<li><a href="#_gtk_builderuser_interfaces_created_with_the_glade_tool">GTK Builder — user interfaces created with the glade tool</a></li>
<li><a href="#_gaction">GAction</a></li>
<li><a href="#_gmenu_with_gactions">GMenu with GActions</a></li>
<li><a href="#_gsettings">GSettings</a></li>
<li><a href="#_drawing_with_cairo_graphics_library">Drawing with Cairo graphics library</a></li>
<li><a href="#_a_simple_listview_example">A simple ListView example</a></li>
<li><a href="#_a_listview_example_with_css_styling">A ListView example with CSS styling</a></li>
<li><a href="#_a_more_advanced_example_for_cairo_drawing_with_zooming_panning_scrolling">A more advanced example for cairo drawing with zooming, panning, scrolling</a></li>
<li><a href="#_one_more_cairo_example">One more cairo example</a></li>
</ul>
</div>
</div>
<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
A more fancy copy of this document with dark source code background is available at <a href="http://ssalewski.de/gintroreadme.html">GIntro README</a>
</td>
</tr>
</table>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
This work is partly based on earlier works of J. Mansour and has been supported by A. Rumpf and other <em>Nim</em> and <em>GTK/Gnome</em> developers.
The <code>combinatorics</code> module was kindly provided by R. Behrends.
</td>
</tr>
</table>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Starting with release 0.5.3 we do not generate field entries for objects and we do
not generate class structs and private objects. Also we stopped exporting the low level functions
like gtk_button_new(). For a real high-level binding we should not need these. If that is a serious
limitation for you, then use release 0.5.2 for now and create an github issue for your use case, we
will try to fix it, maybe undo these changes. Also starting with v0.5.3 we try to support array
parameters like TargetEntryArray, PageRangeArray and KeymapKeyArray. Use of these array parameters is rare,
if you will use functions with these parameters you may inspect the source code first, as the
code is auto-generated and still untested.
</td>
</tr>
</table>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Starting with release 0.5.0 we also support GTK4. GTK4 is still work in progress and not intended for
end users yet, but it is good to have it available for migration testing. For GTK4 we have a new module gsk, and
new versions of modules gtk, gdk and gdkX11, which are not backward compatible with the old once of GTK3. The other
modules can be used by GTK3 and GTK4 in parallel. Due to this fact we use a single nimble package which can be used for
GTK3 and GTK4 development. To archive this, we have named the new modules gtk4, gdk4 and gdkX114 — the
old once are named gtk, gdk and gdkX11 still. So for existing GTK3 software no code changes are necessary.
For GTK4 an example is provided — it imports gtk4 instead of gtk now, and instead of window.showAll()
window.show() is needed. More GTK4 examples may follow eventually, see GTK4 migration page at
<a href="https://developer.gnome.org/gtk4/stable/gtk-migrating-3-to-4.html" class="bare">https://developer.gnome.org/gtk4/stable/gtk-migrating-3-to-4.html</a>. The gintro package tries to install
the GTK4 modules when GTK4 is available on the local computer and skips it if not available.
For successful detection of GTK4 the typelibs must be found. For example, if you have installed
GTK4 from sources on /opt/gtk as described in <a href="https://developer.gnome.org/gtk4/3.96/gtk-building.html" class="bare">https://developer.gnome.org/gtk4/3.96/gtk-building.html</a>, then
you may have to execute "export GI_TYPELIB_PATH=/opt/gtk/lib64/girepository-1.0" in your shell before you
do "nimble install gintro". Currently gtksourceview and vte is not available for GTK4. GTK4 provides a
official test program called gtk4-demo — of course that one should work fine on your box before you
consider testing Nim with GTK4.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p><a href="https://nim-lang.org/">Nim</a> is a modern universal programming language.</p>
</div>
<div class="paragraph">
<p><a href="https://www.gtk.org/">GTK</a>, also known as the <em>Gimp Tool Kit</em> and now sometimes called <em>Gnome Tool Kit</em>, is a Graphical User Interface library.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
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.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>While GTK was initially designed and advertised as cross platform GUI toolkit, it is currently mostly used on <em>Linux</em> and other <em>Unix</em> 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 <em>GIMP</em> are still used on <em>Windows</em>, there seems to exist currently only very few GTK3 applications for Windows or <em>MacOSX</em>.
When you develop primary <em>free open source software</em> (<em>FOSS</em>) 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 MacOSX operating systems. But when your primary target platforms
are Windows and MacOSX 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. <em>Android OS</em> is currently not supported by GTK at all.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
At least for Windows 10 it seems to be not that hard to install GTK3 libraries, as was recently reported in
<a href="https://github.com/StefanSalewski/gintro/issues/24" class="bare">https://github.com/StefanSalewski/gintro/issues/24</a> by user zetashift:
</td>
</tr>
</table>
</div>
<div class="listingblock">
<div class="content">
<pre> Sketch of GTK3 install for Windows 10:
For the GTK libs I did according these instructions(https://www.gtk.org/download/windows.php):
Install MSYS2
In the msys2 cmd I entered:
pacman -S mingw-w64-x86_64-gtk3
Then for some other necessary depencies(girepository.dll) you need to do:
pacman -S mingw-w64-x86_64-python3-gobject
Additional, you have to install the separate GtkSourceView lib in a similar manner from
https://github.com/Alexpux/MINGW-packages/blob/master/mingw-w64-gtksourceview3/</pre>
</div>
</div>
<div class="paragraph">
<p>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 <em>Garbage Collector</em> (<em>GC</em>) support and an idiomatic
<em>Application Programming Interface</em> (<em>API</em>).</p>
</div>
<div class="paragraph">
<p>Currently there are at least 3 sources of GTK3 bindings for Nim:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://github.com/ngtk3" class="bare">https://github.com/ngtk3</a> (obsolete, has been deleted)</p>
</li>
<li>
<p><a href="https://github.com/StefanSalewski/oldgtk3" class="bare">https://github.com/StefanSalewski/oldgtk3</a></p>
</li>
<li>
<p><a href="https://github.com/StefanSalewski/gintro" class="bare">https://github.com/StefanSalewski/gintro</a></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>ngtk3 was the first attempt to provide GTK3 support for Nim. It contained single repositories for all the GTK related libraries and
was not supported by nimble package manager. It was created from GTK 3.20 headers and is now deprecated.</p>
</div>
<div class="paragraph">
<p>oldgtk3 is the port of ngtk3 to GTK 3.22 — joining all libraries and providing nimble support. Some people may still prefer
using oldgtk3. As it is generated with the Nim tool c2nim directly from the C header files without much manual intervention,
it should be complete and contain not that much bugs. 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.</p>
</div>
<div class="paragraph">
<p>Still there can be some demand for really high level bindings — so this gintro repository tries to provide them.</p>
</div>
<div class="paragraph">
<p>High level GTK3 bindings, as available for many other programming languages like <em>C++</em>, <em>Python</em>, <em>Ruby</em> or <em>D</em> already,
have these advantages:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>full Garbage Collector or Destructor support — you should never have to free resources manually</p>
</li>
<li>
<p>Widgets are Nim objects, so inheritance and sub-classing can be used</p>
</li>
<li>
<p>full type safety — no needs for casts or other unsafe and dangerous operations</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>These high level bindings are based on <em>GObject-Introspection</em>, an <em>XML</em> based database like interface description. Compared to the <em>C</em> 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 minimal
modifications also for the upcoming GTK4.</p>
</div>
<div class="paragraph">
<p>Unfortunately there are also some drawbacks:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>The Application Programming Interface (API) will be different from what is known from <em>C</em> API, so using <em>C</em> examples or <em>C</em> tutorials is not really straight forward</p>
</li>
<li>
<p>The high level source code will differ from available <em>C</em> examples, so there would be a big demand for tutorials</p>
</li>
<li>
<p>We need a lot of glue code, which has much room for bugs. So much testing is necessary.</p>
</li>
<li>
<p>There is some overhead due to indirect calls, leading to some code size increase and minimal
performance loss.</p>
</li>
</ul>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
The new package name is <strong>gintro</strong>, short for <em>GObject-Introspection</em>. The previous name was <em>nim-gi</em>, but the hyphen is deprecated for package names, as is the
nim prefix.
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_current_state_of_these_bindings">Current state of these bindings</h2>
<div class="sectionbody">
<div class="paragraph">
<p>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 <code>c2nim</code> tool from the <em>C</em> headers. After that was done, we have associated all
the <em>C</em> structs and <em>GObject</em> data types with Nim proxy objects. A well defined relation between these proxy object and the low level <em>C</em> data types
should ensure fully automatic garbage collection. This is supported by smart type conversion, for example <em>C</em> strings returned by <code>glib</code> library
are assigned to newly created Nim strings, while the memory of the <em>C</em> 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 <em>C</em> strings or other non elementary data types,
or function arguments or results may be so called <em>glists</em>,
list structures of <code>glib</code> 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.</p>
</div>
<div class="paragraph">
<p>These basic libraries are already partly tested:</p>
</div>
<div class="paragraph">
<p>Gtk, Gdk, GLib, GObject, Gio, GdkPixbuf, GtkSource, Pango, PangoCairo, PangoFT2, GModule, Rsvg, fontconfig, freetype2, xlib, Atk, Vte, cairo</p>
</div>
<div class="paragraph">
<p>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 bindings for the <em>cairo</em> drawing library provided by GObject-Introspection was only a minimal stub — we have extend it manually.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_how_to_try_it_out">How to try it out</h2>
<div class="sectionbody">
<div class="paragraph">
<p>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.</p>
</div>
<div class="paragraph">
<p>With a recent nimble version (>= v0.8.10) you only have to type in a shell window:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>nimble install gintro</pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Latest version of gintro package uses some files from oldgtk3 package for bootstrapping. We assume that
users of gintro generally are not interested in low level oldgtk3 package, so we try to download only 3 single files
from oldgtk3 package. That should work if wget or nimgrab executables are available. If it fails you should
get a longer error message which may help you to solve the issue.
</td>
</tr>
</table>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Nimble prepare should run for about 20 seconds, it compiles and executes the generator program <code>gen.nim</code>.
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.
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_a_few_basic_examples">A few basic examples</h2>
<div class="sectionbody">
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Currently we do not install the example programs. If you want to try them, you have to copy the source code of the
examples from <a href="https://github.com/StefanSalewski/gintro/tree/master/examples" class="bare">https://github.com/StefanSalewski/gintro/tree/master/examples</a> to your local computer, maybe to /tmp/gintro/examples directory.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Then you can compile and run them from shell with commands like</p>
</div>
<div class="listingblock">
<div class="content">
<pre>cd /tmp/gintro/examples/
nim c app0.nim
./app0</pre>
</div>
</div>
<div class="paragraph">
<p>or you may open the source files in your favorite Nim IDE or editor. Taking the source code from this Readme file is not
really recommended, as these source code listings may be not the latest versions.</p>
</div>
<div class="paragraph">
<p>GTK3 programs can use still the old <em>GTK2</em> 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 <a href="http://zetcode.com/gui/gtk2/">Zetcode tutorial</a> or in the GTK book of A. Krause.
Or you can use the new <em>GTK3 App style</em>, 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 really easy for beginners to start with GTK. API docs and some basic introduction is available here:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://www.gnome.org/" class="bare">https://www.gnome.org/</a></p>
</li>
<li>
<p><a href="https://www.gtk.org/" class="bare">https://www.gtk.org/</a></p>
</li>
<li>
<p><a href="https://developer.gnome.org/" class="bare">https://developer.gnome.org/</a></p>
</li>
<li>
<p><a href="https://developer.gnome.org/gtk3/stable/" class="bare">https://developer.gnome.org/gtk3/stable/</a></p>
</li>
<li>
<p><a href="https://developer.gnome.org/gtk3/stable/ch01s04.html#id-1.2.3.12.5" class="bare">https://developer.gnome.org/gtk3/stable/ch01s04.html#id-1.2.3.12.5</a></p>
</li>
<li>
<p><a href="https://developer.gnome.org/gnome-devel-demos/stable/c.html.en" class="bare">https://developer.gnome.org/gnome-devel-demos/stable/c.html.en</a></p>
</li>
</ul>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
If you should decide to continue developing software with GTK, then you may consider installing the so called
<code>devhelp</code> tool. It gives you easy and fast access to the GTK API docs. For example, if you want to use a <em>Button Widget</em> in your
GUI and wants to learn more about related functions and signals, you just enter <em>Button</em> in that tool and are guided to
all the relevant information.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>We start with a minimal traditional old style example, which should be familiar to most of us:</p>
</div>
<div id="t0.nim" class="listingblock">
<div class="title">t0.nim</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="nim"><span></span><span class="tok-c"># nim c t0.nim</span>
<span class="tok-kn">import</span> <span class="tok-n">gintro</span><span class="tok-o">/[</span><span class="tok-n">gtk</span><span class="tok-p">,</span> <span class="tok-n">gobject</span><span class="tok-o">]</span>
<span class="tok-k">proc </span><span class="tok-nf">bye</span><span class="tok-p">(</span><span class="tok-n">w</span><span class="tok-p">:</span> <span class="tok-n">Window</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">mainQuit</span><span class="tok-p">()</span>
<span class="tok-n">echo</span> <span class="tok-s">"Bye..."</span>
<span class="tok-k">proc </span><span class="tok-nf">main</span> <span class="tok-o">=</span>
<span class="tok-n">gtk</span><span class="tok-p">.</span><span class="tok-n">init</span><span class="tok-p">()</span>
<span class="tok-k">let</span> <span class="tok-n">window</span> <span class="tok-o">=</span> <span class="tok-n">newWindow</span><span class="tok-p">()</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">title</span> <span class="tok-o">=</span> <span class="tok-s">"First Test"</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-s">"destroy"</span><span class="tok-p">,</span> <span class="tok-n">bye</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">showAll</span>
<span class="tok-n">gtk</span><span class="tok-p">.</span><span class="tok-n">main</span><span class="tok-p">()</span>
<span class="tok-n">main</span><span class="tok-p">()</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>This is the traditional layout of GTK2 programs. When using this style then it is important to initialize the GTK library by calling <code>gtk.init()</code>
at the very beginning. Then we create the desired widgets, connect signals, show all widgets and finally enter the GTK main loop
by calling <code>gtk.main</code>. 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.</p>
</div>
<div class="paragraph">
<p>Now a really minimal but complete App style example, which displays an empty window.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
The source text of all these examples is contained in the examples directory. Unfortunately <em>github</em>
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.
</td>
</tr>
</table>
</div>
<div id="app0.nim" class="listingblock">
<div class="title">app0.nim</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="nim"><span></span><span class="tok-c"># app0.nim -- minimal application style example</span>
<span class="tok-c"># nim c app0.nim</span>
<span class="tok-kn">import</span> <span class="tok-n">gintro</span><span class="tok-o">/[</span><span class="tok-n">gtk</span><span class="tok-p">,</span> <span class="tok-n">glib</span><span class="tok-p">,</span> <span class="tok-n">gobject</span><span class="tok-p">,</span> <span class="tok-n">gio</span><span class="tok-o">]</span>
<span class="tok-k">proc </span><span class="tok-nf">appActivate</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">:</span> <span class="tok-n">Application</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">window</span> <span class="tok-o">=</span> <span class="tok-n">newApplicationWindow</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">title</span> <span class="tok-o">=</span> <span class="tok-s">"GTK3 & Nim"</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">defaultSize</span> <span class="tok-o">=</span> <span class="tok-p">(</span><span class="tok-mi">200</span><span class="tok-p">,</span> <span class="tok-mi">200</span><span class="tok-p">)</span>
<span class="tok-n">showAll</span><span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">main</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">app</span> <span class="tok-o">=</span> <span class="tok-n">newApplication</span><span class="tok-p">(</span><span class="tok-s">"org.gtk.example"</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">,</span> <span class="tok-s">"activate"</span><span class="tok-p">,</span> <span class="tok-n">appActivate</span><span class="tok-p">)</span>
<span class="tok-k">discard</span> <span class="tok-n">run</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-n">main</span><span class="tok-p">()</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>In the <code>main proc</code> we create a new application and connect the activate signal to our <code>activate proc</code>, which then creates and displays
the still empty window.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
We are importing modules gtk and gio. Initially both modules had a data type called <code>Application</code> (<code>gtk.Application</code>
extends indeed the <code>gio.Application</code>), so we would have to use module name prefixes, or we could import from gio only
what is really needed (<code>from gio import …​</code>) or use the form (<code>import gio exept …​</code>). But as gio.Application is generally
not needed often, we have no renamed gio.Application to GApplication. No more name clashes.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Various ways to set widget parameters are supported — the number 1 to 6 refer to the comments below:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="pygments highlight"><code data-lang="nim"><span></span><span class="tok-n">setDefaultSize</span><span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">,</span> <span class="tok-mi">200</span><span class="tok-p">,</span> <span class="tok-mi">200</span><span class="tok-p">)</span> <i class="conum" data-value="1"></i><b>(1)</b>
<span class="tok-n">gtk</span><span class="tok-p">.</span><span class="tok-n">setDefaultSize</span><span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">,</span> <span class="tok-mi">200</span><span class="tok-p">,</span> <span class="tok-mi">200</span><span class="tok-p">)</span> <i class="conum" data-value="2"></i><b>(2)</b>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">setDefaultSize</span><span class="tok-p">(</span><span class="tok-mi">200</span><span class="tok-p">,</span> <span class="tok-mi">200</span><span class="tok-p">)</span> <i class="conum" data-value="3"></i><b>(3)</b>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">setDefaultSize</span><span class="tok-p">(</span><span class="tok-n">width</span> <span class="tok-o">=</span> <span class="tok-mi">200</span><span class="tok-p">,</span> <span class="tok-n">height</span> <span class="tok-o">=</span> <span class="tok-mi">200</span><span class="tok-p">)</span> <i class="conum" data-value="4"></i><b>(4)</b>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">defaultSize</span> <span class="tok-o">=</span> <span class="tok-p">(</span><span class="tok-mi">200</span><span class="tok-p">,</span> <span class="tok-mi">200</span><span class="tok-p">)</span> <i class="conum" data-value="5"></i><b>(5)</b>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">defaultSize</span> <span class="tok-o">=</span> <span class="tok-p">(</span><span class="tok-n">width</span><span class="tok-p">:</span> <span class="tok-mi">200</span><span class="tok-p">,</span> <span class="tok-n">height</span><span class="tok-p">:</span> <span class="tok-mi">200</span><span class="tok-p">)</span> <i class="conum" data-value="6"></i><b>(6)</b></code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>proc call syntax</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>optional qualified with module name prefix</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>method call syntax</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>named parameters</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>tupel assignment</td>
</tr>
<tr>
<td><i class="conum" data-value="6"></i><b>6</b></td>
<td>tupel assignment with named members</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Well, that empty window is really not very interesting. The GTK and Gnome team provides some GTK examples
at <a href="https://developer.gnome.org/gnome-devel-demos/" class="bare">https://developer.gnome.org/gnome-devel-demos/</a>.
The <a href="https://developer.gnome.org/gnome-devel-demos/3.22/c.html.en">C demos</a> 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 <a href="https://developer.gnome.org/gnome-devel-demos/3.22/button.c.html.en" class="bare">https://developer.gnome.org/gnome-devel-demos/3.22/button.c.html.en</a> as it is
still short and easy to understand, but shows already some interesting topics.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="http://ssalewski.de/tmp/NimGTK3Button.png" alt="NimGTK3Button">
</div>
</div>
<div class="paragraph">
<p>The <em>C</em> code looks like this:</p>
</div>
<div id="button.c" class="listingblock">
<div class="title">button.c</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="c"><span></span><span class="tok-cp">#include</span> <span class="tok-cpf"><gtk/gtk.h></span><span class="tok-cp"></span>
<span class="tok-cm">/*This is the callback function. It is a handler function which</span>
<span class="tok-cm">reacts to the signal. In this case, it will cause the button label's</span>
<span class="tok-cm">string to reverse.*/</span>
<span class="tok-k">static</span> <span class="tok-kt">void</span>
<span class="tok-nf">button_clicked</span> <span class="tok-p">(</span><span class="tok-n">GtkButton</span> <span class="tok-o">*</span><span class="tok-n">button</span><span class="tok-p">,</span>
<span class="tok-n">gpointer</span> <span class="tok-n">user_data</span><span class="tok-p">)</span>
<span class="tok-p">{</span>
<span class="tok-k">const</span> <span class="tok-kt">char</span> <span class="tok-o">*</span><span class="tok-n">old_label</span><span class="tok-p">;</span>
<span class="tok-kt">char</span> <span class="tok-o">*</span><span class="tok-n">new_label</span><span class="tok-p">;</span>
<span class="tok-n">old_label</span> <span class="tok-o">=</span> <span class="tok-n">gtk_button_get_label</span> <span class="tok-p">(</span><span class="tok-n">button</span><span class="tok-p">);</span>
<span class="tok-n">new_label</span> <span class="tok-o">=</span> <span class="tok-n">g_utf8_strreverse</span> <span class="tok-p">(</span><span class="tok-n">old_label</span><span class="tok-p">,</span> <span class="tok-o">-</span><span class="tok-mi">1</span><span class="tok-p">);</span>
<span class="tok-n">gtk_button_set_label</span> <span class="tok-p">(</span><span class="tok-n">button</span><span class="tok-p">,</span> <span class="tok-n">new_label</span><span class="tok-p">);</span>
<span class="tok-n">g_free</span> <span class="tok-p">(</span><span class="tok-n">new_label</span><span class="tok-p">);</span>
<span class="tok-p">}</span>
<span class="tok-k">static</span> <span class="tok-kt">void</span>
<span class="tok-nf">activate</span> <span class="tok-p">(</span><span class="tok-n">GtkApplication</span> <span class="tok-o">*</span><span class="tok-n">app</span><span class="tok-p">,</span>
<span class="tok-n">gpointer</span> <span class="tok-n">user_data</span><span class="tok-p">)</span>
<span class="tok-p">{</span>
<span class="tok-n">GtkWidget</span> <span class="tok-o">*</span><span class="tok-n">window</span><span class="tok-p">;</span>
<span class="tok-n">GtkWidget</span> <span class="tok-o">*</span><span class="tok-n">button</span><span class="tok-p">;</span>
<span class="tok-cm">/*Create a window with a title and a default size*/</span>
<span class="tok-n">window</span> <span class="tok-o">=</span> <span class="tok-n">gtk_application_window_new</span> <span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">);</span>
<span class="tok-n">gtk_window_set_title</span> <span class="tok-p">(</span><span class="tok-n">GTK_WINDOW</span> <span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">),</span> <span class="tok-s">"GNOME Button"</span><span class="tok-p">);</span>
<span class="tok-n">gtk_window_set_default_size</span> <span class="tok-p">(</span><span class="tok-n">GTK_WINDOW</span> <span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">),</span> <span class="tok-mi">250</span><span class="tok-p">,</span> <span class="tok-mi">50</span><span class="tok-p">);</span>
<span class="tok-cm">/*Create a button with a label, and add it to the window*/</span>
<span class="tok-n">button</span> <span class="tok-o">=</span> <span class="tok-n">gtk_button_new_with_label</span> <span class="tok-p">(</span><span class="tok-s">"Click Me"</span><span class="tok-p">);</span>
<span class="tok-n">gtk_container_add</span> <span class="tok-p">(</span><span class="tok-n">GTK_CONTAINER</span> <span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">),</span> <span class="tok-n">button</span><span class="tok-p">);</span>
<span class="tok-cm">/*Connecting the clicked signal to the callback function*/</span>
<span class="tok-n">g_signal_connect</span> <span class="tok-p">(</span><span class="tok-n">GTK_BUTTON</span> <span class="tok-p">(</span><span class="tok-n">button</span><span class="tok-p">),</span>
<span class="tok-s">"clicked"</span><span class="tok-p">,</span>
<span class="tok-n">G_CALLBACK</span> <span class="tok-p">(</span><span class="tok-n">button_clicked</span><span class="tok-p">),</span>
<span class="tok-n">G_OBJECT</span> <span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">));</span>
<span class="tok-n">gtk_widget_show_all</span> <span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">);</span>
<span class="tok-p">}</span>
<span class="tok-kt">int</span>
<span class="tok-nf">main</span> <span class="tok-p">(</span><span class="tok-kt">int</span> <span class="tok-n">argc</span><span class="tok-p">,</span> <span class="tok-kt">char</span> <span class="tok-o">**</span><span class="tok-n">argv</span><span class="tok-p">)</span>
<span class="tok-p">{</span>
<span class="tok-n">GtkApplication</span> <span class="tok-o">*</span><span class="tok-n">app</span><span class="tok-p">;</span>
<span class="tok-kt">int</span> <span class="tok-n">status</span><span class="tok-p">;</span>
<span class="tok-n">app</span> <span class="tok-o">=</span> <span class="tok-n">gtk_application_new</span> <span class="tok-p">(</span><span class="tok-s">"org.gtk.example"</span><span class="tok-p">,</span> <span class="tok-n">G_APPLICATION_FLAGS_NONE</span><span class="tok-p">);</span>
<span class="tok-n">g_signal_connect</span> <span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">,</span> <span class="tok-s">"activate"</span><span class="tok-p">,</span> <span class="tok-n">G_CALLBACK</span> <span class="tok-p">(</span><span class="tok-n">activate</span><span class="tok-p">),</span> <span class="tok-nb">NULL</span><span class="tok-p">);</span>
<span class="tok-n">status</span> <span class="tok-o">=</span> <span class="tok-n">g_application_run</span> <span class="tok-p">(</span><span class="tok-n">G_APPLICATION</span> <span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">),</span> <span class="tok-n">argc</span><span class="tok-p">,</span> <span class="tok-n">argv</span><span class="tok-p">);</span>
<span class="tok-n">g_object_unref</span> <span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">);</span>
<span class="tok-k">return</span> <span class="tok-n">status</span><span class="tok-p">;</span>
<span class="tok-p">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Converting it to Nim is straight forward with some basic <em>C</em> and Nim knowledge, and Nim does not force us
to convert its shape into all the classes known from pure <em>Object Orientated</em> (<em>OO</em>) languages. We can either use the
Nim tool <code>c2nim</code> to help us with the conversion, or do it manually. Indeed <code>c2nim</code> can be very helpful by
converting <em>C</em> sources to Nim. Most of the time it works well. Personally I generally pre-process <em>C</em> files, for example
by removing too strange <code>macros</code> and <code>defines, or by replacing strange constructs, like <em>C</em> `for loops</code>, to simpler
ones like <code>while loops</code>. Then I apply <code>c2nim</code> to the <em>C</em> 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:</p>
</div>
<div id="button.nim" class="listingblock">
<div class="title">button.nim</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="nim"><span></span><span class="tok-c"># nim c button.nim</span>
<span class="tok-kn">import</span> <span class="tok-n">gintro</span><span class="tok-o">/[</span><span class="tok-n">gtk</span><span class="tok-p">,</span> <span class="tok-n">glib</span><span class="tok-p">,</span> <span class="tok-n">gobject</span><span class="tok-p">,</span> <span class="tok-n">gio</span><span class="tok-o">]</span>
<span class="tok-k">proc </span><span class="tok-nf">buttonClicked</span> <span class="tok-p">(</span><span class="tok-n">button</span><span class="tok-p">:</span> <span class="tok-n">Button</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">button</span><span class="tok-p">.</span><span class="tok-n">label</span> <span class="tok-o">=</span> <span class="tok-n">utf8Strreverse</span><span class="tok-p">(</span><span class="tok-n">button</span><span class="tok-p">.</span><span class="tok-n">label</span><span class="tok-p">,</span> <span class="tok-o">-</span><span class="tok-mi">1</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">appActivate</span> <span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">:</span> <span class="tok-n">Application</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">window</span> <span class="tok-o">=</span> <span class="tok-n">newApplicationWindow</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">title</span> <span class="tok-o">=</span> <span class="tok-s">"GNOME Button"</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">defaultSize</span> <span class="tok-o">=</span> <span class="tok-p">(</span><span class="tok-mi">250</span><span class="tok-p">,</span> <span class="tok-mi">50</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">button</span> <span class="tok-o">=</span> <span class="tok-n">newButton</span><span class="tok-p">(</span><span class="tok-s">"Click Me"</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">add</span><span class="tok-p">(</span><span class="tok-n">button</span><span class="tok-p">)</span>
<span class="tok-n">button</span><span class="tok-p">.</span><span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-s">"clicked"</span><span class="tok-p">,</span> <span class="tok-n">buttonClicked</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">showAll</span>
<span class="tok-k">proc </span><span class="tok-nf">main</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">app</span> <span class="tok-o">=</span> <span class="tok-n">newApplication</span><span class="tok-p">(</span><span class="tok-s">"org.gtk.example"</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">,</span> <span class="tok-s">"activate"</span><span class="tok-p">,</span> <span class="tok-n">appActivate</span><span class="tok-p">)</span>
<span class="tok-k">discard</span> <span class="tok-n">app</span><span class="tok-p">.</span><span class="tok-n">run</span>
<span class="tok-n">main</span><span class="tok-p">()</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Again we have the basic shape already known from <a href="#app0.nim">app0.nim</a> example: <code>Main proc</code> creates the application, connect
to the activate signal and finally runs the application. When GTK launches the application and emits the <code>activate</code> 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 <code>clicked</code>. That signal is emitted by GTK whenever that button is clicked with the mouse and results
in a call of our provided <code>buttonClicked()</code> proc. The procs connected to signals are called <em>callbacks</em> 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 <em>glib</em> function <code>utf8Strreverse()</code>
for this task. While that function internally works with <code>cstrings</code>, and in <em>C</em> we have to free the memory of the returned <code>cstring</code>,
in our Nim example that is done automatically by Nim’s Garbage Collector. When you compare our example carefully with the <em>C</em> code,
then you may notice a difference. The <em>C</em> 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.
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 <em>C</em> code returns an <code>integer</code> status value returned by <code>g_application_run()</code> to the <em>OS</em>. We
could do the same by using the <code>quit() proc</code> of Nim’s <em>OS</em> module, but as that would give us no additional benefit, we simply ignore it.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
The command <code>nim c sourcetext.nim</code> 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 <code>-d:release</code> to avoid this. For the <code>gcc</code> backend
you may additional enable <em>Link Time Optimization</em> (<em>LTO</em>), which reduces executable size further. To enable LTO you may put
a <code>nim.cfg</code> file in your sources directory with content like
</td>
</tr>
</table>
</div>
<div class="listingblock">
<div class="content">
<pre>path:"$projectdir"
nimcache:"/tmp/$projectdir"
gcc.options.speed = "-march=native -O3 -flto -fstrict-aliasing"</pre>
</div>
</div>
<div class="paragraph">
<p>With that optimization, your executable sizes should be in the range of about 50 kB only!</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_optional_type_safe_parameters_for_callbacks">Optional, type safe parameters for callbacks</h2>
<div class="sectionbody">
<div class="paragraph">
<p>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 <code>bin</code> and can contain only one
single child widget, we create a container widget, a vertical box in this case, fill that box with
some buttons, and add that box to the window.</p>
</div>
<div class="paragraph">
<p>Compile and start this example from the command line and watch what
happens when you click on the buttons.</p>
</div>
<div id="connect_args.nim" class="listingblock">
<div class="title">connect_args.nim</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="nim"><span></span><span class="tok-c"># nim c connect_args.nim</span>
<span class="tok-kn">import</span> <span class="tok-n">gintro</span><span class="tok-o">/[</span><span class="tok-n">gtk</span><span class="tok-p">,</span> <span class="tok-n">glib</span><span class="tok-p">,</span> <span class="tok-n">gobject</span><span class="tok-p">,</span> <span class="tok-n">gio</span><span class="tok-o">]</span>
<span class="tok-k">type</span>
<span class="tok-n">O</span> <span class="tok-o">=</span> <span class="tok-k">object</span>
<span class="tok-n">i</span><span class="tok-p">:</span> <span class="tok-kt">int</span>
<span class="tok-k">proc </span><span class="tok-nf">b1Callback</span><span class="tok-p">(</span><span class="tok-n">button</span><span class="tok-p">:</span> <span class="tok-n">Button</span><span class="tok-p">;</span> <span class="tok-n">str</span><span class="tok-p">:</span> <span class="tok-kt">string</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">echo</span> <span class="tok-n">str</span>
<span class="tok-k">proc </span><span class="tok-nf">b2Callback</span><span class="tok-p">(</span><span class="tok-n">button</span><span class="tok-p">:</span> <span class="tok-n">Button</span><span class="tok-p">;</span> <span class="tok-n">o</span><span class="tok-p">:</span> <span class="tok-n">O</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">echo</span> <span class="tok-s">"Value of field i in object o = "</span><span class="tok-p">,</span> <span class="tok-n">o</span><span class="tok-p">.</span><span class="tok-n">i</span>
<span class="tok-k">proc </span><span class="tok-nf">b3Callback</span><span class="tok-p">(</span><span class="tok-n">button</span><span class="tok-p">:</span> <span class="tok-n">Button</span><span class="tok-p">;</span> <span class="tok-n">r</span><span class="tok-p">:</span> <span class="tok-k">ref</span> <span class="tok-n">O</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">echo</span> <span class="tok-s">"Value of field i in ref to object O = "</span><span class="tok-p">,</span> <span class="tok-n">r</span><span class="tok-p">.</span><span class="tok-n">i</span>
<span class="tok-k">proc </span><span class="tok-nf">b4Callback</span><span class="tok-p">(</span><span class="tok-n">button</span><span class="tok-p">:</span> <span class="tok-n">Button</span><span class="tok-p">;</span> <span class="tok-n">w</span><span class="tok-p">:</span> <span class="tok-n">ApplicationWindow</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-k">if</span> <span class="tok-n">w</span><span class="tok-p">.</span><span class="tok-n">title</span> <span class="tok-o">==</span> <span class="tok-s">"Nim with GTK3"</span><span class="tok-p">:</span>
<span class="tok-n">w</span><span class="tok-p">.</span><span class="tok-n">title</span> <span class="tok-o">=</span> <span class="tok-s">"GTK3 with Nim"</span>
<span class="tok-k">else</span><span class="tok-p">:</span>
<span class="tok-n">w</span><span class="tok-p">.</span><span class="tok-n">title</span> <span class="tok-o">=</span> <span class="tok-s">"Nim with GTK3"</span>
<span class="tok-k">proc </span><span class="tok-nf">appActivate</span> <span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">:</span> <span class="tok-n">Application</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-kd">var</span> <span class="tok-n">o</span><span class="tok-p">:</span> <span class="tok-n">O</span>
<span class="tok-kd">var</span> <span class="tok-n">r</span><span class="tok-p">:</span> <span class="tok-k">ref</span> <span class="tok-n">O</span>
<span class="tok-n">new</span> <span class="tok-n">r</span>
<span class="tok-n">o</span><span class="tok-p">.</span><span class="tok-n">i</span> <span class="tok-o">=</span> <span class="tok-mi">1234567</span>
<span class="tok-n">r</span><span class="tok-p">.</span><span class="tok-n">i</span> <span class="tok-o">=</span> <span class="tok-mi">7654321</span>
<span class="tok-k">let</span> <span class="tok-n">window</span> <span class="tok-o">=</span> <span class="tok-n">newApplicationWindow</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">box</span> <span class="tok-o">=</span> <span class="tok-n">newBox</span><span class="tok-p">(</span><span class="tok-n">Orientation</span><span class="tok-p">.</span><span class="tok-n">vertical</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">title</span> <span class="tok-o">=</span> <span class="tok-s">"Parameters for callbacks"</span>
<span class="tok-k">let</span> <span class="tok-n">b1</span> <span class="tok-o">=</span> <span class="tok-n">newButton</span><span class="tok-p">(</span><span class="tok-s">"Nim with GTK3"</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">b2</span> <span class="tok-o">=</span> <span class="tok-n">newButton</span><span class="tok-p">(</span><span class="tok-s">"Passing an object from stack"</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">b3</span> <span class="tok-o">=</span> <span class="tok-n">newButton</span><span class="tok-p">(</span><span class="tok-s">"Passing an object from heap"</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">b4</span> <span class="tok-o">=</span> <span class="tok-n">newButton</span><span class="tok-p">(</span><span class="tok-s">"Passing a Widget"</span><span class="tok-p">)</span>
<span class="tok-n">b1</span><span class="tok-p">.</span><span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-s">"clicked"</span><span class="tok-p">,</span> <span class="tok-n">b1Callback</span><span class="tok-p">,</span> <span class="tok-s">"is much fun."</span><span class="tok-p">)</span>
<span class="tok-n">b2</span><span class="tok-p">.</span><span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-s">"clicked"</span><span class="tok-p">,</span> <span class="tok-n">b2Callback</span><span class="tok-p">,</span> <span class="tok-n">o</span><span class="tok-p">)</span>
<span class="tok-n">b3</span><span class="tok-p">.</span><span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-s">"clicked"</span><span class="tok-p">,</span> <span class="tok-n">b3Callback</span><span class="tok-p">,</span> <span class="tok-n">r</span><span class="tok-p">)</span>
<span class="tok-n">b4</span><span class="tok-p">.</span><span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-s">"clicked"</span><span class="tok-p">,</span> <span class="tok-n">b4Callback</span><span class="tok-p">,</span> <span class="tok-n">window</span><span class="tok-p">)</span>
<span class="tok-n">box</span><span class="tok-p">.</span><span class="tok-n">add</span><span class="tok-p">(</span><span class="tok-n">b1</span><span class="tok-p">)</span>
<span class="tok-n">box</span><span class="tok-p">.</span><span class="tok-n">add</span><span class="tok-p">(</span><span class="tok-n">b2</span><span class="tok-p">)</span>
<span class="tok-n">box</span><span class="tok-p">.</span><span class="tok-n">add</span><span class="tok-p">(</span><span class="tok-n">b3</span><span class="tok-p">)</span>
<span class="tok-n">box</span><span class="tok-p">.</span><span class="tok-n">add</span><span class="tok-p">(</span><span class="tok-n">b4</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">add</span><span class="tok-p">(</span><span class="tok-n">box</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">showAll</span>
<span class="tok-k">proc </span><span class="tok-nf">main</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">app</span> <span class="tok-o">=</span> <span class="tok-n">newApplication</span><span class="tok-p">(</span><span class="tok-s">"org.gtk.example"</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">,</span> <span class="tok-s">"activate"</span><span class="tok-p">,</span> <span class="tok-n">appActivate</span><span class="tok-p">)</span>
<span class="tok-k">discard</span> <span class="tok-n">app</span><span class="tok-p">.</span><span class="tok-n">run</span>
<span class="tok-n">main</span><span class="tok-p">()</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>To prove type safety, we may modify one of the callback procs and watch the compiler output:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="pygments highlight"><code data-lang="nim"><span></span><span class="tok-k">proc </span><span class="tok-nf">b1Callback</span><span class="tok-p">(</span><span class="tok-n">button</span><span class="tok-p">:</span> <span class="tok-n">Button</span><span class="tok-p">;</span> <span class="tok-n">str</span><span class="tok-p">:</span> <span class="tok-kt">int</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-k">discard</span> <span class="tok-c"># echo str</span></code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre>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)</pre>
</div>
</div>
<div class="paragraph">
<p>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.</p>
</div>
<div class="paragraph">
<p>Currently the connect function is realized by a Nim type safe <code>macro</code>. 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 <code>r</code> and the <code>window</code> variables 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.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
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 <code>nimsuggest</code> support further supports navigation — for example <code>NEd</code> shows us
all the needed proc parameters when we move the cursor on a proc name, or we press <span class="keyseq"><kbd>Ctrl</kbd>+<kbd>W</kbd></span> and jump
to the definition of that symbol. For unknown stuff the original <em>C</em> 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 <code>new</code> in their name.
So it is easy to guess that there exists a <em>C</em> function named <code>gtk_button_new</code>. That name is also
contained in the bindings files, in this case in <code>gtk.nim</code>. 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 <code>devhelp</code> tool, and use also <code>grep</code> or the <code>nimgrep</code> variant.
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_extending_or_sub_classing_widgets">Extending or sub-classing Widgets</h2>
<div class="sectionbody">
<div class="paragraph">
<p>I may occur that we want to attach additional information to GTK widgets
by extending or subclassing them. Doing this is supported
by providing for each widget class not only a corresponding new() proc which returns
the newly created widget, but also
a init() proc, which gets an uninitialized variable of the (extended) widget type as argument and
initializes that variable with a newly created
GTK widget . Initializing the added fields is
done separately by the user. The following code shows a GTK button, which is
extended with a counter member field. That counter is decreased for
each button click. The amount of decrease (5) is passed to the callback as a int parameter.</p>
</div>
<div id="count_button.nim" class="listingblock">
<div class="title">count_button.nim</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="nim"><span></span><span class="tok-c"># nim c count_button.nim</span>
<span class="tok-kn">import</span> <span class="tok-n">gintro</span><span class="tok-o">/[</span><span class="tok-n">gtk</span><span class="tok-p">,</span> <span class="tok-n">glib</span><span class="tok-p">,</span> <span class="tok-n">gobject</span><span class="tok-p">,</span> <span class="tok-n">gio</span><span class="tok-o">]</span>
<span class="tok-k">type</span>
<span class="tok-n">CountButton</span> <span class="tok-o">=</span> <span class="tok-k">ref</span> <span class="tok-k">object</span> <span class="tok-k">of</span> <span class="tok-n">Button</span>
<span class="tok-n">counter</span><span class="tok-p">:</span> <span class="tok-kt">int</span>
<span class="tok-k">proc </span><span class="tok-nf">buttonClicked</span> <span class="tok-p">(</span><span class="tok-n">button</span><span class="tok-p">:</span> <span class="tok-n">CountButton</span><span class="tok-p">;</span> <span class="tok-n">decrement</span><span class="tok-p">:</span> <span class="tok-kt">int</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">dec</span><span class="tok-p">(</span><span class="tok-n">button</span><span class="tok-p">.</span><span class="tok-n">counter</span><span class="tok-p">,</span> <span class="tok-n">decrement</span><span class="tok-p">)</span>
<span class="tok-n">button</span><span class="tok-p">.</span><span class="tok-n">label</span> <span class="tok-o">=</span> <span class="tok-s">"Counter: "</span> <span class="tok-o">&</span> <span class="tok-o">$</span><span class="tok-n">button</span><span class="tok-p">.</span><span class="tok-n">counter</span>
<span class="tok-n">echo</span> <span class="tok-s">"Counter is now: "</span><span class="tok-p">,</span> <span class="tok-n">button</span><span class="tok-p">.</span><span class="tok-n">counter</span>
<span class="tok-k">proc </span><span class="tok-nf">appActivate</span> <span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">:</span> <span class="tok-n">Application</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-kd">var</span> <span class="tok-n">button</span><span class="tok-p">:</span> <span class="tok-n">CountButton</span>
<span class="tok-k">let</span> <span class="tok-n">window</span> <span class="tok-o">=</span> <span class="tok-n">newApplicationWindow</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">title</span> <span class="tok-o">=</span> <span class="tok-s">"Count Button"</span>
<span class="tok-n">initButton</span><span class="tok-p">(</span><span class="tok-n">button</span><span class="tok-p">,</span> <span class="tok-s">"Counting down from 100 by 5"</span><span class="tok-p">)</span>
<span class="tok-n">button</span><span class="tok-p">.</span><span class="tok-n">counter</span> <span class="tok-o">=</span> <span class="tok-mi">100</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">add</span><span class="tok-p">(</span><span class="tok-n">button</span><span class="tok-p">)</span>
<span class="tok-n">button</span><span class="tok-p">.</span><span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-s">"clicked"</span><span class="tok-p">,</span> <span class="tok-n">buttonClicked</span><span class="tok-p">,</span> <span class="tok-mi">5</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">showAll</span>
<span class="tok-k">proc </span><span class="tok-nf">main</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">app</span> <span class="tok-o">=</span> <span class="tok-n">newApplication</span><span class="tok-p">(</span><span class="tok-s">"org.gtk.example"</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">,</span> <span class="tok-s">"activate"</span><span class="tok-p">,</span> <span class="tok-n">appActivate</span><span class="tok-p">)</span>
<span class="tok-k">discard</span> <span class="tok-n">app</span><span class="tok-p">.</span><span class="tok-n">run</span>
<span class="tok-n">main</span><span class="tok-p">()</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>In this example we have to define our new widget type first, then we have to
declare a variable of that type and pass that variable to the init() proc.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_css_styles_gerrors_and_exceptions">CSS styles, GErrors and Exceptions</h2>
<div class="sectionbody">
<div class="imageblock">
<div class="content">
<img src="http://ssalewski.de/tmp/NimGTK3Label.png" alt="NimGTK3Label">
</div>
</div>
<div class="paragraph">
<p>Often GTK beginners ask how one can apply custom styles to GTK widgets, for example custom colors.
While in most cases the use of custom colors gives just ugly results, as the custom colors generally do
not match well with the default color scheme, it is good to know how we can do it. For GTK3 styles are
applied to widgets by using <em>Cascading Style Sheets</em> (<em>CSS</em>). You may find C example code similar to this:</p>
</div>
<div id="label.c" class="listingblock">
<div class="title">label.c</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="c"><span></span><span class="tok-c1">// https://stackoverflow.com/questions/30791670/how-to-style-a-gtklabel-with-css</span>
<span class="tok-c1">// gcc `pkg-config gtk+-3.0 --cflags` test.c -o test `pkg-config --libs gtk+-3.0`</span>
<span class="tok-cp">#include</span> <span class="tok-cpf"><gtk/gtk.h></span><span class="tok-cp"></span>
<span class="tok-kt">int</span> <span class="tok-nf">main</span><span class="tok-p">(</span><span class="tok-kt">int</span> <span class="tok-n">argc</span><span class="tok-p">,</span> <span class="tok-kt">char</span> <span class="tok-o">*</span><span class="tok-n">argv</span><span class="tok-p">[])</span> <span class="tok-p">{</span>
<span class="tok-n">gtk_init</span><span class="tok-p">(</span><span class="tok-o">&</span><span class="tok-n">argc</span><span class="tok-p">,</span> <span class="tok-o">&</span><span class="tok-n">argv</span><span class="tok-p">);</span>
<span class="tok-n">GtkWidget</span> <span class="tok-o">*</span><span class="tok-n">window</span> <span class="tok-o">=</span> <span class="tok-n">gtk_window_new</span><span class="tok-p">(</span><span class="tok-n">GTK_WINDOW_TOPLEVEL</span><span class="tok-p">);</span>
<span class="tok-n">GtkWidget</span> <span class="tok-o">*</span><span class="tok-n">label</span> <span class="tok-o">=</span> <span class="tok-n">gtk_label_new</span><span class="tok-p">(</span><span class="tok-s">"Label"</span><span class="tok-p">);</span>
<span class="tok-n">GtkCssProvider</span> <span class="tok-o">*</span><span class="tok-n">cssProvider</span> <span class="tok-o">=</span> <span class="tok-n">gtk_css_provider_new</span><span class="tok-p">();</span>
<span class="tok-kt">char</span> <span class="tok-o">*</span><span class="tok-n">data</span> <span class="tok-o">=</span> <span class="tok-s">"label {color: green;}"</span><span class="tok-p">;</span>
<span class="tok-n">gtk_css_provider_load_from_data</span><span class="tok-p">(</span><span class="tok-n">cssProvider</span><span class="tok-p">,</span> <span class="tok-n">data</span><span class="tok-p">,</span> <span class="tok-o">-</span><span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-nb">NULL</span><span class="tok-p">);</span>
<span class="tok-n">gtk_style_context_add_provider</span><span class="tok-p">(</span><span class="tok-n">gtk_widget_get_style_context</span><span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">),</span>
<span class="tok-n">GTK_STYLE_PROVIDER</span><span class="tok-p">(</span><span class="tok-n">cssProvider</span><span class="tok-p">),</span>
<span class="tok-n">GTK_STYLE_PROVIDER_PRIORITY_USER</span><span class="tok-p">);</span>
<span class="tok-n">g_signal_connect</span><span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">,</span> <span class="tok-s">"destroy"</span><span class="tok-p">,</span> <span class="tok-n">G_CALLBACK</span><span class="tok-p">(</span><span class="tok-n">gtk_main_quit</span><span class="tok-p">),</span> <span class="tok-nb">NULL</span><span class="tok-p">);</span>
<span class="tok-n">gtk_container_add</span><span class="tok-p">(</span><span class="tok-n">GTK_CONTAINER</span><span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">),</span> <span class="tok-n">label</span><span class="tok-p">);</span>
<span class="tok-n">gtk_widget_show_all</span><span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">);</span>
<span class="tok-n">gtk_main</span><span class="tok-p">();</span>
<span class="tok-p">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Converting that to Nim is again straight forward:</p>
</div>
<div id="label.nim" class="listingblock">
<div class="title">label.nim</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="nim"><span></span><span class="tok-c"># nim c label.nim</span>
<span class="tok-kn">import</span> <span class="tok-n">gintro</span><span class="tok-o">/[</span><span class="tok-n">gtk</span><span class="tok-p">,</span> <span class="tok-n">glib</span><span class="tok-p">,</span> <span class="tok-n">gobject</span><span class="tok-p">,</span> <span class="tok-n">gio</span><span class="tok-o">]</span>
<span class="tok-k">proc </span><span class="tok-nf">appActivate</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">:</span> <span class="tok-n">Application</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">window</span> <span class="tok-o">=</span> <span class="tok-n">newApplicationWindow</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">label</span> <span class="tok-o">=</span> <span class="tok-n">newLabel</span><span class="tok-p">(</span><span class="tok-s">"Yellow text on green background"</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">cssProvider</span> <span class="tok-o">=</span> <span class="tok-n">newCssProvider</span><span class="tok-p">()</span>
<span class="tok-k">let</span> <span class="tok-n">data</span> <span class="tok-o">=</span> <span class="tok-s">"label {color: yellow; background: green;}"</span>
<span class="tok-c">#discard cssProvider.loadFromPath("doesnotexist")</span>
<span class="tok-k">discard</span> <span class="tok-n">cssProvider</span><span class="tok-p">.</span><span class="tok-n">loadFromData</span><span class="tok-p">(</span><span class="tok-n">data</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">styleContext</span> <span class="tok-o">=</span> <span class="tok-n">label</span><span class="tok-p">.</span><span class="tok-n">getStyleContext</span>
<span class="tok-n">assert</span> <span class="tok-n">styleContext</span> <span class="tok-o">!=</span> <span class="tok-kp">nil</span>
<span class="tok-n">addProvider</span><span class="tok-p">(</span><span class="tok-n">styleContext</span><span class="tok-p">,</span> <span class="tok-n">cssProvider</span><span class="tok-p">,</span> <span class="tok-n">STYLE_PROVIDER_PRIORITY_USER</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">add</span><span class="tok-p">(</span><span class="tok-n">label</span><span class="tok-p">)</span>
<span class="tok-n">showAll</span><span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">main</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">app</span> <span class="tok-o">=</span> <span class="tok-n">newApplication</span><span class="tok-p">(</span><span class="tok-s">"org.gtk.example"</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">,</span> <span class="tok-s">"activate"</span><span class="tok-p">,</span> <span class="tok-n">appActivate</span><span class="tok-p">)</span>
<span class="tok-k">discard</span> <span class="tok-n">run</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-n">main</span><span class="tok-p">()</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>For this example we create a plain label widget with some text. To colorize it, we generate a
CssProvider and load it with a textual description of our desired colors. Then we extract the
style context from the label and add our CssProvider to it.</p>
</div>
<div class="paragraph">
<p>The last parameter of the <em>C</em> function gtk_css_provider_load_from_data() is of type GError and can
be used in <em>C</em> code to detect runtime errors. The <em>C</em> code above just passes NULL to ignore this error.
For Nim we map that GError argument to <em>exceptions</em>. To test what happens in Nim when an GError would
report an error condition, you may uncomment function loadFromPath() in the code above. As the specified path
does not exist, we should get an exception with a message telling us the problem. Of course in your real
code you may catch such exceptions with Nim’s <code>try:</code> blocks. (You may also modify the data variable above to
an illegal CSS statement — if the statement is seriously wrong, then you should get an exception from
loadFromData().</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_gtk_builderuser_interfaces_created_with_the_glade_tool">GTK Builder — user interfaces created with the glade tool</h2>
<div class="sectionbody">
<div class="paragraph">
<p>As C code can be very verbose, some people prefer outsourcing the GUI layout
in XML files which can be created and modified with the glade GUI creator program.
For high level languages like Python or Nim the program source code is generally
short and clean, so that use of XML files may not have much benefit. But of course
we can use GTK builder from Nim. We follow the example from
<a href="https://developer.gnome.org/gtk3/stable/ch01s03.html" class="bare">https://developer.gnome.org/gtk3/stable/ch01s03.html</a>
but we modify it to use the new GTK3 app style: For the XML file we have to change only
class="GtkWindow" into class="GtkApplicationWindow". Our Nim program has
the well known application shape, with one addition: We have to
explicitly set the application for the main window. Of course you can also
use the traditional program structure with Nim and Builder, for that case
you can straight follow the linked page or other examples. Here is the XML file and the Nim code:</p>
</div>
<div id="builder.ui" class="listingblock">
<div class="title">builder.ui</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="xml"><span></span><span class="tok-nt"><interface></span>
<span class="tok-nt"><object</span> <span class="tok-na">id=</span><span class="tok-s">"window"</span> <span class="tok-na">class=</span><span class="tok-s">"GtkApplicationWindow"</span><span class="tok-nt">></span>
<span class="tok-nt"><property</span> <span class="tok-na">name=</span><span class="tok-s">"visible"</span><span class="tok-nt">></span>True<span class="tok-nt"></property></span>
<span class="tok-nt"><property</span> <span class="tok-na">name=</span><span class="tok-s">"title"</span><span class="tok-nt">></span>Grid<span class="tok-nt"></property></span>
<span class="tok-nt"><property</span> <span class="tok-na">name=</span><span class="tok-s">"border-width"</span><span class="tok-nt">></span>10<span class="tok-nt"></property></span>
<span class="tok-nt"><child></span>
<span class="tok-nt"><object</span> <span class="tok-na">id=</span><span class="tok-s">"grid"</span> <span class="tok-na">class=</span><span class="tok-s">"GtkGrid"</span><span class="tok-nt">></span>
<span class="tok-nt"><property</span> <span class="tok-na">name=</span><span class="tok-s">"visible"</span><span class="tok-nt">></span>True<span class="tok-nt"></property></span>
<span class="tok-nt"><child></span>
<span class="tok-nt"><object</span> <span class="tok-na">id=</span><span class="tok-s">"button1"</span> <span class="tok-na">class=</span><span class="tok-s">"GtkButton"</span><span class="tok-nt">></span>
<span class="tok-nt"><property</span> <span class="tok-na">name=</span><span class="tok-s">"visible"</span><span class="tok-nt">></span>True<span class="tok-nt"></property></span>
<span class="tok-nt"><property</span> <span class="tok-na">name=</span><span class="tok-s">"label"</span><span class="tok-nt">></span>Button 1<span class="tok-nt"></property></span>
<span class="tok-nt"></object></span>
<span class="tok-nt"><packing></span>
<span class="tok-nt"><property</span> <span class="tok-na">name=</span><span class="tok-s">"left-attach"</span><span class="tok-nt">></span>0<span class="tok-nt"></property></span>
<span class="tok-nt"><property</span> <span class="tok-na">name=</span><span class="tok-s">"top-attach"</span><span class="tok-nt">></span>0<span class="tok-nt"></property></span>
<span class="tok-nt"></packing></span>
<span class="tok-nt"></child></span>
<span class="tok-nt"><child></span>
<span class="tok-nt"><object</span> <span class="tok-na">id=</span><span class="tok-s">"button2"</span> <span class="tok-na">class=</span><span class="tok-s">"GtkButton"</span><span class="tok-nt">></span>
<span class="tok-nt"><property</span> <span class="tok-na">name=</span><span class="tok-s">"visible"</span><span class="tok-nt">></span>True<span class="tok-nt"></property></span>
<span class="tok-nt"><property</span> <span class="tok-na">name=</span><span class="tok-s">"label"</span><span class="tok-nt">></span>Button 2<span class="tok-nt"></property></span>
<span class="tok-nt"></object></span>
<span class="tok-nt"><packing></span>
<span class="tok-nt"><property</span> <span class="tok-na">name=</span><span class="tok-s">"left-attach"</span><span class="tok-nt">></span>1<span class="tok-nt"></property></span>
<span class="tok-nt"><property</span> <span class="tok-na">name=</span><span class="tok-s">"top-attach"</span><span class="tok-nt">></span>0<span class="tok-nt"></property></span>
<span class="tok-nt"></packing></span>
<span class="tok-nt"></child></span>
<span class="tok-nt"><child></span>
<span class="tok-nt"><object</span> <span class="tok-na">id=</span><span class="tok-s">"quit"</span> <span class="tok-na">class=</span><span class="tok-s">"GtkButton"</span><span class="tok-nt">></span>
<span class="tok-nt"><property</span> <span class="tok-na">name=</span><span class="tok-s">"visible"</span><span class="tok-nt">></span>True<span class="tok-nt"></property></span>
<span class="tok-nt"><property</span> <span class="tok-na">name=</span><span class="tok-s">"label"</span><span class="tok-nt">></span>Quit<span class="tok-nt"></property></span>
<span class="tok-nt"></object></span>
<span class="tok-nt"><packing></span>
<span class="tok-nt"><property</span> <span class="tok-na">name=</span><span class="tok-s">"left-attach"</span><span class="tok-nt">></span>0<span class="tok-nt"></property></span>
<span class="tok-nt"><property</span> <span class="tok-na">name=</span><span class="tok-s">"top-attach"</span><span class="tok-nt">></span>1<span class="tok-nt"></property></span>
<span class="tok-nt"><property</span> <span class="tok-na">name=</span><span class="tok-s">"width"</span><span class="tok-nt">></span>2<span class="tok-nt"></property></span>
<span class="tok-nt"></packing></span>
<span class="tok-nt"></child></span>
<span class="tok-nt"></object></span>
<span class="tok-nt"><packing></span>
<span class="tok-nt"></packing></span>
<span class="tok-nt"></child></span>
<span class="tok-nt"></object></span>
<span class="tok-nt"></interface></span></code></pre>
</div>
</div>
<div id="builder.nim" class="listingblock">
<div class="title">builder.nim</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="nim"><span></span> <span class="tok-n">https</span><span class="tok-p">:</span><span class="tok-o">//</span><span class="tok-n">developer</span><span class="tok-p">.</span><span class="tok-n">gnome</span><span class="tok-p">.</span><span class="tok-n">org</span><span class="tok-o">/</span><span class="tok-n">gtk3</span><span class="tok-o">/</span><span class="tok-n">stable</span><span class="tok-o">/</span><span class="tok-n">ch01s03</span><span class="tok-p">.</span><span class="tok-n">html</span>
<span class="tok-c"># builder.nim -- application style example using builder/glade xml file for user interface</span>
<span class="tok-c"># nim c builder.nim</span>
<span class="tok-kn">import</span> <span class="tok-n">gintro</span><span class="tok-o">/[</span><span class="tok-n">gtk</span><span class="tok-p">,</span> <span class="tok-n">glib</span><span class="tok-p">,</span> <span class="tok-n">gobject</span><span class="tok-p">,</span> <span class="tok-n">gio</span><span class="tok-o">]</span>
<span class="tok-k">proc </span><span class="tok-nf">hello</span><span class="tok-p">(</span><span class="tok-n">b</span><span class="tok-p">:</span> <span class="tok-n">Button</span><span class="tok-p">;</span> <span class="tok-n">msg</span><span class="tok-p">:</span> <span class="tok-kt">string</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">echo</span> <span class="tok-s">"Hello"</span><span class="tok-p">,</span> <span class="tok-n">msg</span>
<span class="tok-k">proc </span><span class="tok-nf">quitApp</span><span class="tok-p">(</span><span class="tok-n">b</span><span class="tok-p">:</span> <span class="tok-n">Button</span><span class="tok-p">;</span> <span class="tok-n">app</span><span class="tok-p">:</span> <span class="tok-n">Application</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">echo</span> <span class="tok-s">"Bye"</span>
<span class="tok-n">quit</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">appActivate</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">:</span> <span class="tok-n">Application</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">builder</span> <span class="tok-o">=</span> <span class="tok-n">newBuilder</span><span class="tok-p">()</span>
<span class="tok-k">discard</span> <span class="tok-n">builder</span><span class="tok-p">.</span><span class="tok-n">addFromFile</span><span class="tok-p">(</span><span class="tok-s">"builder.ui"</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">window</span> <span class="tok-o">=</span> <span class="tok-n">builder</span><span class="tok-p">.</span><span class="tok-n">getApplicationWindow</span><span class="tok-p">(</span><span class="tok-s">"window"</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">setApplication</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-kd">var</span> <span class="tok-n">button</span> <span class="tok-o">=</span> <span class="tok-n">builder</span><span class="tok-p">.</span><span class="tok-n">getButton</span><span class="tok-p">(</span><span class="tok-s">"button1"</span><span class="tok-p">)</span>
<span class="tok-n">button</span><span class="tok-p">.</span><span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-s">"clicked"</span><span class="tok-p">,</span> <span class="tok-n">hello</span><span class="tok-p">,</span> <span class="tok-s">""</span><span class="tok-p">)</span>
<span class="tok-n">button</span> <span class="tok-o">=</span> <span class="tok-n">builder</span><span class="tok-p">.</span><span class="tok-n">getButton</span><span class="tok-p">(</span><span class="tok-s">"button2"</span><span class="tok-p">)</span>
<span class="tok-n">button</span><span class="tok-p">.</span><span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-s">"clicked"</span><span class="tok-p">,</span> <span class="tok-n">hello</span><span class="tok-p">,</span> <span class="tok-s">" again..."</span><span class="tok-p">)</span>
<span class="tok-n">button</span> <span class="tok-o">=</span> <span class="tok-n">builder</span><span class="tok-p">.</span><span class="tok-n">getButton</span><span class="tok-p">(</span><span class="tok-s">"quit"</span><span class="tok-p">)</span>
<span class="tok-n">button</span><span class="tok-p">.</span><span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-s">"clicked"</span><span class="tok-p">,</span> <span class="tok-n">quitApp</span><span class="tok-p">,</span> <span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-c">#showAll(window)</span>
<span class="tok-k">proc </span><span class="tok-nf">main</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">app</span> <span class="tok-o">=</span> <span class="tok-n">newApplication</span><span class="tok-p">(</span><span class="tok-s">"org.gtk.example"</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">,</span> <span class="tok-s">"activate"</span><span class="tok-p">,</span> <span class="tok-n">appActivate</span><span class="tok-p">)</span>
<span class="tok-k">discard</span> <span class="tok-n">run</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-n">main</span><span class="tok-p">()</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>For each builder component gintro provides a typesafe access proc like
getApplicationWindow() and getButton() in this example.</p>
</div>
<div class="paragraph">
<p>Generally it is possible to use resource files merged with the executable program
instead of an external XML files, we have to investigate how we can do that in Nim.
And it may be possible to connect the signal handlers to handler procs from within
the XML file — this is also work in progress…​</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_gaction">GAction</h2>
<div class="sectionbody">
<div class="paragraph">
<p>GAction represents a single named action and is for GTK3 the prefered way to do
user interactions. GAction works with button, menus and keyboard shortcuts.</p>
</div>
<div class="paragraph">
<p>The following example is based on</p>
</div>
<div class="paragraph">
<p><a href="https://wiki.gnome.org/HowDoI/GAction" class="bare">https://wiki.gnome.org/HowDoI/GAction</a></p>
</div>
<div id="gaction.nim" class="listingblock">
<div class="title">gaction.nim</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="nim"><span></span><span class="tok-c"># https://wiki.gnome.org/HowDoI/GAction</span>
<span class="tok-c"># nim c gaction.nim</span>
<span class="tok-kn">import</span> <span class="tok-n">gintro</span><span class="tok-o">/[</span><span class="tok-n">gtk</span><span class="tok-p">,</span> <span class="tok-n">glib</span><span class="tok-p">,</span> <span class="tok-n">gobject</span><span class="tok-p">,</span> <span class="tok-n">gio</span><span class="tok-o">]</span>
<span class="tok-k">proc </span><span class="tok-nf">saveCb</span><span class="tok-p">(</span><span class="tok-n">action</span><span class="tok-p">:</span> <span class="tok-n">SimpleAction</span><span class="tok-p">;</span> <span class="tok-n">v</span><span class="tok-p">:</span> <span class="tok-n">Variant</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">echo</span> <span class="tok-s">"saveCb"</span>
<span class="tok-k">proc </span><span class="tok-nf">appActivate</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">:</span> <span class="tok-n">Application</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">window</span> <span class="tok-o">=</span> <span class="tok-n">newApplicationWindow</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">action</span> <span class="tok-o">=</span> <span class="tok-n">newSimpleAction</span><span class="tok-p">(</span><span class="tok-s">"save"</span><span class="tok-p">)</span>
<span class="tok-k">discard</span> <span class="tok-n">action</span><span class="tok-p">.</span><span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-s">"activate"</span><span class="tok-p">,</span> <span class="tok-n">saveCB</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">actionMap</span><span class="tok-p">.</span><span class="tok-n">addAction</span><span class="tok-p">(</span><span class="tok-n">action</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">button</span> <span class="tok-o">=</span> <span class="tok-n">newButton</span><span class="tok-p">()</span>
<span class="tok-n">button</span><span class="tok-p">.</span><span class="tok-n">label</span> <span class="tok-o">=</span> <span class="tok-s">"Save"</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">add</span><span class="tok-p">(</span><span class="tok-n">button</span><span class="tok-p">)</span>
<span class="tok-n">button</span><span class="tok-p">.</span><span class="tok-n">setActionName</span><span class="tok-p">(</span><span class="tok-s">"win.save"</span><span class="tok-p">)</span>
<span class="tok-n">setAccelsForAction</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">,</span> <span class="tok-s">"win.save"</span><span class="tok-p">,</span> <span class="tok-s">"<Control><Shift>S"</span><span class="tok-p">)</span>
<span class="tok-n">showAll</span><span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">main</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">app</span> <span class="tok-o">=</span> <span class="tok-n">newApplication</span><span class="tok-p">(</span><span class="tok-s">"org.gtk.example"</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">,</span> <span class="tok-s">"activate"</span><span class="tok-p">,</span> <span class="tok-n">appActivate</span><span class="tok-p">)</span>
<span class="tok-k">discard</span> <span class="tok-n">run</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-n">main</span><span class="tok-p">()</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>GtkApplicationWindow provides an interface to GActionMap. As
the interface itself and the interface provider are defined in different modules,
automatic conversion is not possible, so we have to convert the ApplicationWindow
to ActionMap. (We could use a converter to do the conversion for us, but as
these conversions are rare, and because gintro use no converters at all still, we use
an explicit proc.) The use of cstringArray as third parameter for proc setAccelsForAction()
is a bit ugly, we have to fix that later.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_gmenu_with_gactions">GMenu with GActions</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The following example shows how we can define GActions and bind them to Menus, Buttons
and Keyboard shortcuts. Examples for stateless actions (quit), for toggle actions (spellcheck)
and for statefull actions (text justify) are provided.</p>
</div>
<div class="paragraph">
<p>Note that the following code is not a direct translation of an existing example, but
a collections of informations from various sources, so
it may contain bugs or not fully optimal code.</p>
</div>
<div id="menubar.nim" class="listingblock">
<div class="title">menubar.nim</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="nim"><span></span><span class="tok-c"># https://developer.gnome.org/glib/stable/glib-GVariant.html</span>
<span class="tok-c"># https://developer.gnome.org/glib/stable/glib-GVariantType.html</span>
<span class="tok-c"># https://wiki.gnome.org/HowDoI/GMenu</span>
<span class="tok-c"># https://wiki.gnome.org/HowDoI/GAction</span>
<span class="tok-c"># nim c menubar.nim</span>
<span class="tok-kn">import</span> <span class="tok-n">gintro</span><span class="tok-o">/[</span><span class="tok-n">gtk</span><span class="tok-p">,</span> <span class="tok-n">glib</span><span class="tok-p">,</span> <span class="tok-n">gobject</span><span class="tok-p">,</span> <span class="tok-n">gio</span><span class="tok-o">]</span>
<span class="tok-kn">from</span> <span class="tok-n">strutils</span> <span class="tok-kn">import</span> <span class="tok-p">`</span><span class="tok-o">%</span><span class="tok-p">`,</span> <span class="tok-n">format</span>
<span class="tok-c"># https://github.com/GNOME/glib/blob/master/gio/tests/gapplication-example-actions.c</span>
<span class="tok-k">proc </span><span class="tok-nf">activateToggleAction</span><span class="tok-p">(</span><span class="tok-n">action</span><span class="tok-p">:</span> <span class="tok-n">SimpleAction</span><span class="tok-p">;</span> <span class="tok-n">parameter</span><span class="tok-p">:</span> <span class="tok-n">Variant</span><span class="tok-p">;</span> <span class="tok-n">app</span><span class="tok-p">:</span> <span class="tok-n">Application</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">app</span><span class="tok-p">.</span><span class="tok-n">hold</span> <span class="tok-c"># hold/release taken over from C example, there may be reasons...</span>
<span class="tok-k">block</span><span class="tok-p">:</span>
<span class="tok-n">echo</span> <span class="tok-n">format</span><span class="tok-p">(</span><span class="tok-s">"action </span><span class="tok-si">$1</span><span class="tok-s"> activated"</span><span class="tok-p">,</span> <span class="tok-n">action</span><span class="tok-p">.</span><span class="tok-n">name</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">state</span><span class="tok-p">:</span> <span class="tok-n">Variant</span> <span class="tok-o">=</span> <span class="tok-n">action</span><span class="tok-p">.</span><span class="tok-n">state</span>
<span class="tok-k">let</span> <span class="tok-n">b</span> <span class="tok-o">=</span> <span class="tok-n">state</span><span class="tok-p">.</span><span class="tok-n">getBoolean</span>
<span class="tok-n">action</span><span class="tok-p">.</span><span class="tok-n">state</span> <span class="tok-o">=</span> <span class="tok-n">newVariantBoolean</span><span class="tok-p">(</span><span class="tok-ow">not</span> <span class="tok-n">b</span><span class="tok-p">)</span>
<span class="tok-n">echo</span> <span class="tok-n">format</span><span class="tok-p">(</span><span class="tok-s">"state change </span><span class="tok-si">$1</span><span class="tok-s"> -> </span><span class="tok-si">$2</span><span class="tok-s">"</span><span class="tok-p">,</span> <span class="tok-n">b</span><span class="tok-p">,</span> <span class="tok-ow">not</span> <span class="tok-n">b</span><span class="tok-p">)</span>
<span class="tok-n">app</span><span class="tok-p">.</span><span class="tok-n">release</span>
<span class="tok-k">proc </span><span class="tok-nf">activateStatefulAction</span><span class="tok-p">(</span><span class="tok-n">action</span><span class="tok-p">:</span> <span class="tok-n">SimpleAction</span><span class="tok-p">;</span> <span class="tok-n">parameter</span><span class="tok-p">:</span> <span class="tok-n">Variant</span><span class="tok-p">;</span> <span class="tok-n">app</span><span class="tok-p">:</span> <span class="tok-n">Application</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">app</span><span class="tok-p">.</span><span class="tok-n">hold</span>
<span class="tok-k">block</span><span class="tok-p">:</span>
<span class="tok-n">echo</span> <span class="tok-n">format</span><span class="tok-p">(</span><span class="tok-s">"action </span><span class="tok-si">$1</span><span class="tok-s"> activated"</span><span class="tok-p">,</span> <span class="tok-n">action</span><span class="tok-p">.</span><span class="tok-n">name</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">state</span><span class="tok-p">:</span> <span class="tok-n">Variant</span> <span class="tok-o">=</span> <span class="tok-n">action</span><span class="tok-p">.</span><span class="tok-n">state</span>
<span class="tok-kd">var</span> <span class="tok-n">l</span><span class="tok-p">:</span> <span class="tok-n">uint64</span>
<span class="tok-k">let</span> <span class="tok-n">oldState</span> <span class="tok-o">=</span> <span class="tok-n">state</span><span class="tok-p">.</span><span class="tok-n">getString</span><span class="tok-p">(</span><span class="tok-n">l</span><span class="tok-p">)</span> <span class="tok-c"># yes uint64 parameter is a bit ugly</span>
<span class="tok-k">let</span> <span class="tok-n">newState</span> <span class="tok-o">=</span> <span class="tok-n">parameter</span><span class="tok-p">.</span><span class="tok-n">getString</span><span class="tok-p">(</span><span class="tok-n">l</span><span class="tok-p">)</span>
<span class="tok-n">action</span><span class="tok-p">.</span><span class="tok-n">state</span> <span class="tok-o">=</span> <span class="tok-n">newVariantString</span><span class="tok-p">(</span><span class="tok-n">newState</span><span class="tok-p">)</span>
<span class="tok-n">echo</span> <span class="tok-n">format</span><span class="tok-p">(</span><span class="tok-s">"state change </span><span class="tok-si">$1</span><span class="tok-s"> -> </span><span class="tok-si">$2</span><span class="tok-s">"</span><span class="tok-p">,</span> <span class="tok-n">oldState</span><span class="tok-p">,</span> <span class="tok-n">newState</span><span class="tok-p">)</span>
<span class="tok-n">app</span><span class="tok-p">.</span><span class="tok-n">release</span>
<span class="tok-k">proc </span><span class="tok-nf">quitProgram</span><span class="tok-p">(</span><span class="tok-n">action</span><span class="tok-p">:</span> <span class="tok-n">SimpleAction</span><span class="tok-p">;</span> <span class="tok-n">parameter</span><span class="tok-p">:</span> <span class="tok-n">Variant</span><span class="tok-p">;</span> <span class="tok-n">app</span><span class="tok-p">:</span> <span class="tok-n">Application</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">quit</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">appStartup</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">:</span> <span class="tok-n">Application</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">quit</span> <span class="tok-o">=</span> <span class="tok-n">newSimpleAction</span><span class="tok-p">(</span><span class="tok-s">"quit"</span><span class="tok-p">)</span> <span class="tok-c"># here we create the actions for whole app</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">quit</span><span class="tok-p">,</span> <span class="tok-s">"activate"</span><span class="tok-p">,</span> <span class="tok-n">quitProgram</span><span class="tok-p">,</span> <span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-n">app</span><span class="tok-p">.</span><span class="tok-n">addAction</span><span class="tok-p">(</span><span class="tok-n">quit</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">menu</span> <span class="tok-o">=</span> <span class="tok-n">gio</span><span class="tok-p">.</span><span class="tok-n">newMenu</span><span class="tok-p">()</span> <span class="tok-c"># root of all menus</span>
<span class="tok-k">block</span><span class="tok-p">:</span> <span class="tok-c"># plain stateless menu</span>
<span class="tok-k">let</span> <span class="tok-n">subMenu</span> <span class="tok-o">=</span> <span class="tok-n">gio</span><span class="tok-p">.</span><span class="tok-n">newMenu</span><span class="tok-p">()</span>
<span class="tok-n">menu</span><span class="tok-p">.</span><span class="tok-n">appendSubMenu</span><span class="tok-p">(</span><span class="tok-s">"Application"</span><span class="tok-p">,</span> <span class="tok-n">submenu</span><span class="tok-p">)</span>
<span class="tok-c"># let section = gio.newMenu() # no separating section needed here</span>
<span class="tok-c"># submenu.appendSection(nil, section)</span>
<span class="tok-c"># section.append("Quit", "app.quit")</span>
<span class="tok-n">submenu</span><span class="tok-p">.</span><span class="tok-n">append</span><span class="tok-p">(</span><span class="tok-s">"Quit"</span><span class="tok-p">,</span> <span class="tok-s">"app.quit"</span><span class="tok-p">)</span>
<span class="tok-k">block</span><span class="tok-p">:</span> <span class="tok-c">#stateful menu with radio items</span>
<span class="tok-k">let</span> <span class="tok-n">subMenu</span> <span class="tok-o">=</span> <span class="tok-n">gio</span><span class="tok-p">.</span><span class="tok-n">newMenu</span><span class="tok-p">()</span>
<span class="tok-n">menu</span><span class="tok-p">.</span><span class="tok-n">appendSubMenu</span><span class="tok-p">(</span><span class="tok-s">"Layout"</span><span class="tok-p">,</span> <span class="tok-n">submenu</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">subMenu2</span> <span class="tok-o">=</span> <span class="tok-n">gio</span><span class="tok-p">.</span><span class="tok-n">newMenu</span><span class="tok-p">()</span>
<span class="tok-n">submenu</span><span class="tok-p">.</span><span class="tok-n">appendSubMenu</span><span class="tok-p">(</span><span class="tok-s">"justify"</span><span class="tok-p">,</span> <span class="tok-n">submenu2</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">section</span> <span class="tok-o">=</span> <span class="tok-n">gio</span><span class="tok-p">.</span><span class="tok-n">newMenu</span><span class="tok-p">()</span>
<span class="tok-n">submenu2</span><span class="tok-p">.</span><span class="tok-n">appendSection</span><span class="tok-p">(</span><span class="tok-kp">nil</span><span class="tok-p">,</span> <span class="tok-n">section</span><span class="tok-p">)</span>
<span class="tok-n">section</span><span class="tok-p">.</span><span class="tok-n">append</span><span class="tok-p">(</span><span class="tok-s">"left"</span><span class="tok-p">,</span> <span class="tok-s">"win.justify::left"</span><span class="tok-p">)</span>
<span class="tok-n">section</span><span class="tok-p">.</span><span class="tok-n">append</span><span class="tok-p">(</span><span class="tok-s">"center"</span><span class="tok-p">,</span> <span class="tok-s">"win.justify::center"</span><span class="tok-p">)</span>
<span class="tok-n">section</span><span class="tok-p">.</span><span class="tok-n">append</span><span class="tok-p">(</span><span class="tok-s">"right"</span><span class="tok-p">,</span> <span class="tok-s">"win.justify::right"</span><span class="tok-p">)</span>
<span class="tok-k">block</span><span class="tok-p">:</span> <span class="tok-c"># and finally a toggle menu</span>
<span class="tok-k">let</span> <span class="tok-n">subMenu</span> <span class="tok-o">=</span> <span class="tok-n">gio</span><span class="tok-p">.</span><span class="tok-n">newMenu</span><span class="tok-p">()</span>
<span class="tok-n">menu</span><span class="tok-p">.</span><span class="tok-n">appendSubMenu</span><span class="tok-p">(</span><span class="tok-s">"Spelling"</span><span class="tok-p">,</span> <span class="tok-n">submenu</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">section</span> <span class="tok-o">=</span> <span class="tok-n">gio</span><span class="tok-p">.</span><span class="tok-n">newMenu</span><span class="tok-p">()</span>
<span class="tok-n">submenu</span><span class="tok-p">.</span><span class="tok-n">appendSection</span><span class="tok-p">(</span><span class="tok-kp">nil</span><span class="tok-p">,</span> <span class="tok-n">section</span><span class="tok-p">)</span>
<span class="tok-n">section</span><span class="tok-p">.</span><span class="tok-n">append</span><span class="tok-p">(</span><span class="tok-s">"Check"</span><span class="tok-p">,</span> <span class="tok-s">"win.toggleSpellCheck"</span><span class="tok-p">)</span>
<span class="tok-c"># finally add the menubar</span>
<span class="tok-n">setMenuBar</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">,</span> <span class="tok-n">menu</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">appActivate</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">:</span> <span class="tok-n">Application</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">window</span> <span class="tok-o">=</span> <span class="tok-n">newApplicationWindow</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">title</span> <span class="tok-o">=</span> <span class="tok-s">"GTK3 App with Menubar"</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">defaultSize</span> <span class="tok-o">=</span> <span class="tok-p">(</span><span class="tok-mi">500</span><span class="tok-p">,</span> <span class="tok-mi">200</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">position</span> <span class="tok-o">=</span> <span class="tok-n">WindowPosition</span><span class="tok-p">.</span><span class="tok-n">center</span>
<span class="tok-k">block</span><span class="tok-p">:</span> <span class="tok-c"># creat the window related actions</span>
<span class="tok-k">let</span> <span class="tok-n">v</span> <span class="tok-o">=</span> <span class="tok-n">newVariantBoolean</span><span class="tok-p">(</span><span class="tok-kp">true</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">spellCheck</span> <span class="tok-o">=</span> <span class="tok-n">newSimpleActionStateful</span><span class="tok-p">(</span><span class="tok-s">"toggleSpellCheck"</span><span class="tok-p">,</span> <span class="tok-kp">nil</span><span class="tok-p">,</span> <span class="tok-n">v</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">spellCheck</span><span class="tok-p">,</span> <span class="tok-s">"activate"</span><span class="tok-p">,</span> <span class="tok-n">activateToggleAction</span><span class="tok-p">,</span> <span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">actionMap</span><span class="tok-p">.</span><span class="tok-n">addAction</span><span class="tok-p">(</span><span class="tok-n">spellCheck</span><span class="tok-p">)</span>
<span class="tok-k">block</span><span class="tok-p">:</span>
<span class="tok-k">let</span> <span class="tok-n">v</span> <span class="tok-o">=</span> <span class="tok-n">newVariantString</span><span class="tok-p">(</span><span class="tok-s">"left"</span><span class="tok-p">)</span> <span class="tok-c"># default value and</span>
<span class="tok-k">let</span> <span class="tok-n">vt</span> <span class="tok-o">=</span> <span class="tok-n">newVariantType</span><span class="tok-p">(</span><span class="tok-s">"s"</span><span class="tok-p">)</span> <span class="tok-c"># string (value type)</span>
<span class="tok-k">let</span> <span class="tok-n">justifyAction</span> <span class="tok-o">=</span> <span class="tok-n">newSimpleActionStateful</span><span class="tok-p">(</span><span class="tok-s">"justify"</span><span class="tok-p">,</span> <span class="tok-n">vt</span><span class="tok-p">,</span> <span class="tok-n">v</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">justifyAction</span><span class="tok-p">,</span> <span class="tok-s">"activate"</span><span class="tok-p">,</span> <span class="tok-n">activateStatefulAction</span><span class="tok-p">,</span> <span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">actionMap</span><span class="tok-p">.</span><span class="tok-n">addAction</span><span class="tok-p">(</span><span class="tok-n">justifyAction</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">button</span> <span class="tok-o">=</span> <span class="tok-n">newButton</span><span class="tok-p">()</span>
<span class="tok-n">button</span><span class="tok-p">.</span><span class="tok-n">label</span> <span class="tok-o">=</span> <span class="tok-s">"Justify Center"</span>
<span class="tok-c">#window.add(button) # do not add it here already: (menubar:10010): Gtk-WARNING **:</span>
<span class="tok-c"># 22:00:33.230: actionhelper: action win.justify can't be activated due to</span>
<span class="tok-c"># parameter type mismatch (parameter type s, target type NULL)</span>
<span class="tok-n">button</span><span class="tok-p">.</span><span class="tok-n">setDetailedActionName</span><span class="tok-p">(</span><span class="tok-s">"win.justify::center"</span><span class="tok-p">)</span>
<span class="tok-c">#button.setActionName("app.quit") # for a stateless action</span>
<span class="tok-n">setAccelsForAction</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">,</span> <span class="tok-s">"win.justify::right"</span><span class="tok-p">,</span> <span class="tok-s">"<Control><Shift>R"</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">add</span><span class="tok-p">(</span><span class="tok-n">button</span><span class="tok-p">)</span>
<span class="tok-n">showAll</span><span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">main</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">app</span> <span class="tok-o">=</span> <span class="tok-n">newApplication</span><span class="tok-p">(</span><span class="tok-s">"app.example"</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">,</span> <span class="tok-s">"startup"</span><span class="tok-p">,</span> <span class="tok-n">appStartup</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">,</span> <span class="tok-s">"activate"</span><span class="tok-p">,</span> <span class="tok-n">appActivate</span><span class="tok-p">)</span>
<span class="tok-n">echo</span> <span class="tok-s">"GTK Version </span><span class="tok-si">$1</span><span class="tok-s">.</span><span class="tok-si">$2</span><span class="tok-s">.</span><span class="tok-si">$3</span><span class="tok-s">"</span> <span class="tok-o">%</span> <span class="tok-o">[$</span><span class="tok-n">majorVersion</span><span class="tok-p">(),</span> <span class="tok-o">$</span><span class="tok-n">minorVersion</span><span class="tok-p">(),</span> <span class="tok-o">$</span><span class="tok-n">microVersion</span><span class="tok-p">()</span><span class="tok-o">]</span>
<span class="tok-k">let</span> <span class="tok-n">status</span> <span class="tok-o">=</span> <span class="tok-n">run</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-n">quit</span><span class="tok-p">(</span><span class="tok-n">status</span><span class="tok-p">)</span>
<span class="tok-n">main</span><span class="tok-p">()</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>We can easily modify the above example to get the more modern look with
a HeaderBar and the "Gears" MenuButtons:</p>
</div>
<div id="gearsmenu.nim" class="listingblock">
<div class="title">gearsmenu.nim</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="nim"><span></span><span class="tok-c"># https://developer.gnome.org/glib/stable/glib-GVariant.html</span>
<span class="tok-c"># https://developer.gnome.org/glib/stable/glib-GVariantType.html</span>
<span class="tok-c"># https://wiki.gnome.org/HowDoI/GMenu</span>
<span class="tok-c"># https://wiki.gnome.org/HowDoI/GAction</span>
<span class="tok-c"># https://developer.gnome.org/gnome-devel-demos/stable/menubutton.c.html.en</span>
<span class="tok-c"># nim c gearsmenu.nim</span>
<span class="tok-kn">import</span> <span class="tok-n">gintro</span><span class="tok-o">/[</span><span class="tok-n">gtk</span><span class="tok-p">,</span> <span class="tok-n">glib</span><span class="tok-p">,</span> <span class="tok-n">gobject</span><span class="tok-p">,</span> <span class="tok-n">gio</span><span class="tok-o">]</span>
<span class="tok-kn">import</span> <span class="tok-n">strformat</span>
<span class="tok-c"># https://github.com/GNOME/glib/blob/master/gio/tests/gapplication-example-actions.c</span>
<span class="tok-k">proc </span><span class="tok-nf">activateToggleAction</span><span class="tok-p">(</span><span class="tok-n">action</span><span class="tok-p">:</span> <span class="tok-n">SimpleAction</span><span class="tok-p">;</span> <span class="tok-n">parameter</span><span class="tok-p">:</span> <span class="tok-n">Variant</span><span class="tok-p">;</span> <span class="tok-n">app</span><span class="tok-p">:</span> <span class="tok-n">Application</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">app</span><span class="tok-p">.</span><span class="tok-n">hold</span> <span class="tok-c"># hold/release taken over from C example, there may be reasons...</span>
<span class="tok-k">block</span><span class="tok-p">:</span>
<span class="tok-n">echo</span> <span class="tok-s">fmt"action {action.name} activated"</span>
<span class="tok-k">let</span> <span class="tok-n">state</span><span class="tok-p">:</span> <span class="tok-n">Variant</span> <span class="tok-o">=</span> <span class="tok-n">action</span><span class="tok-p">.</span><span class="tok-n">state</span>
<span class="tok-k">let</span> <span class="tok-n">b</span> <span class="tok-o">=</span> <span class="tok-n">state</span><span class="tok-p">.</span><span class="tok-n">getBoolean</span>
<span class="tok-n">action</span><span class="tok-p">.</span><span class="tok-n">state</span> <span class="tok-o">=</span> <span class="tok-n">newVariantBoolean</span><span class="tok-p">(</span><span class="tok-ow">not</span> <span class="tok-n">b</span><span class="tok-p">)</span>
<span class="tok-n">echo</span> <span class="tok-s">fmt"state change {b} -> {not b}"</span>
<span class="tok-n">app</span><span class="tok-p">.</span><span class="tok-n">release</span>
<span class="tok-k">proc </span><span class="tok-nf">activateStatefulAction</span><span class="tok-p">(</span><span class="tok-n">action</span><span class="tok-p">:</span> <span class="tok-n">SimpleAction</span><span class="tok-p">;</span> <span class="tok-n">parameter</span><span class="tok-p">:</span> <span class="tok-n">Variant</span><span class="tok-p">;</span> <span class="tok-n">app</span><span class="tok-p">:</span> <span class="tok-n">Application</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">app</span><span class="tok-p">.</span><span class="tok-n">hold</span>
<span class="tok-k">block</span><span class="tok-p">:</span>
<span class="tok-n">echo</span> <span class="tok-s">fmt"action {action.name} activated"</span>
<span class="tok-k">let</span> <span class="tok-n">state</span><span class="tok-p">:</span> <span class="tok-n">Variant</span> <span class="tok-o">=</span> <span class="tok-n">action</span><span class="tok-p">.</span><span class="tok-n">state</span>
<span class="tok-kd">var</span> <span class="tok-n">l</span><span class="tok-p">:</span> <span class="tok-n">uint64</span>
<span class="tok-k">let</span> <span class="tok-n">oldState</span> <span class="tok-o">=</span> <span class="tok-n">state</span><span class="tok-p">.</span><span class="tok-n">getString</span><span class="tok-p">(</span><span class="tok-n">l</span><span class="tok-p">)</span> <span class="tok-c"># yes uint64 parameter is a bit ugly</span>
<span class="tok-k">let</span> <span class="tok-n">newState</span> <span class="tok-o">=</span> <span class="tok-n">parameter</span><span class="tok-p">.</span><span class="tok-n">getString</span><span class="tok-p">(</span><span class="tok-n">l</span><span class="tok-p">)</span>
<span class="tok-n">action</span><span class="tok-p">.</span><span class="tok-n">state</span> <span class="tok-o">=</span> <span class="tok-n">newVariantString</span><span class="tok-p">(</span><span class="tok-n">newState</span><span class="tok-p">)</span>
<span class="tok-n">echo</span> <span class="tok-s">fmt"state change {oldState} -> {newState}"</span>
<span class="tok-n">app</span><span class="tok-p">.</span><span class="tok-n">release</span>
<span class="tok-k">proc </span><span class="tok-nf">quitProgram</span><span class="tok-p">(</span><span class="tok-n">action</span><span class="tok-p">:</span> <span class="tok-n">SimpleAction</span><span class="tok-p">;</span> <span class="tok-n">parameter</span><span class="tok-p">:</span> <span class="tok-n">Variant</span><span class="tok-p">;</span> <span class="tok-n">app</span><span class="tok-p">:</span> <span class="tok-n">Application</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">quit</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">appStartup</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">:</span> <span class="tok-n">Application</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">echo</span> <span class="tok-s">"appStartup"</span>
<span class="tok-k">let</span> <span class="tok-n">quit</span> <span class="tok-o">=</span> <span class="tok-n">newSimpleAction</span><span class="tok-p">(</span><span class="tok-s">"quit"</span><span class="tok-p">)</span> <span class="tok-c"># here we create the actions for whole app</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">quit</span><span class="tok-p">,</span> <span class="tok-s">"activate"</span><span class="tok-p">,</span> <span class="tok-n">quitProgram</span><span class="tok-p">,</span> <span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-n">app</span><span class="tok-p">.</span><span class="tok-n">addAction</span><span class="tok-p">(</span><span class="tok-n">quit</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">appActivate</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">:</span> <span class="tok-n">Application</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">echo</span> <span class="tok-s">"appActivate"</span>
<span class="tok-k">let</span> <span class="tok-n">window</span> <span class="tok-o">=</span> <span class="tok-n">newApplicationWindow</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-c"># window.title = "GTK3 App with Headerbar and Gears Menu" # unused due to HeaderBar</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">defaultSize</span> <span class="tok-o">=</span> <span class="tok-p">(</span><span class="tok-mi">500</span><span class="tok-p">,</span> <span class="tok-mi">200</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">position</span> <span class="tok-o">=</span> <span class="tok-n">WindowPosition</span><span class="tok-p">.</span><span class="tok-n">center</span>
<span class="tok-k">let</span> <span class="tok-n">menu</span> <span class="tok-o">=</span> <span class="tok-n">gio</span><span class="tok-p">.</span><span class="tok-n">newMenu</span><span class="tok-p">()</span> <span class="tok-c"># root of all menus</span>
<span class="tok-k">block</span><span class="tok-p">:</span> <span class="tok-c"># plain stateless menu</span>
<span class="tok-k">let</span> <span class="tok-n">subMenu</span> <span class="tok-o">=</span> <span class="tok-n">gio</span><span class="tok-p">.</span><span class="tok-n">newMenu</span><span class="tok-p">()</span>
<span class="tok-n">menu</span><span class="tok-p">.</span><span class="tok-n">appendSubMenu</span><span class="tok-p">(</span><span class="tok-s">"Application"</span><span class="tok-p">,</span> <span class="tok-n">submenu</span><span class="tok-p">)</span>
<span class="tok-c"># let section = gio.newMenu() # no separating section needed here</span>
<span class="tok-c"># submenu.appendSection(nil, section)</span>
<span class="tok-c"># section.append("Quit", "app.quit")</span>
<span class="tok-n">submenu</span><span class="tok-p">.</span><span class="tok-n">append</span><span class="tok-p">(</span><span class="tok-s">"Quit"</span><span class="tok-p">,</span> <span class="tok-s">"app.quit"</span><span class="tok-p">)</span>
<span class="tok-k">block</span><span class="tok-p">:</span> <span class="tok-c">#stateful menu with radio items</span>
<span class="tok-k">let</span> <span class="tok-n">subMenu</span> <span class="tok-o">=</span> <span class="tok-n">gio</span><span class="tok-p">.</span><span class="tok-n">newMenu</span><span class="tok-p">()</span>
<span class="tok-n">menu</span><span class="tok-p">.</span><span class="tok-n">appendSubMenu</span><span class="tok-p">(</span><span class="tok-s">"Layout"</span><span class="tok-p">,</span> <span class="tok-n">submenu</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">subMenu2</span> <span class="tok-o">=</span> <span class="tok-n">gio</span><span class="tok-p">.</span><span class="tok-n">newMenu</span><span class="tok-p">()</span>
<span class="tok-n">submenu</span><span class="tok-p">.</span><span class="tok-n">appendSubMenu</span><span class="tok-p">(</span><span class="tok-s">"justify"</span><span class="tok-p">,</span> <span class="tok-n">submenu2</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">section</span> <span class="tok-o">=</span> <span class="tok-n">gio</span><span class="tok-p">.</span><span class="tok-n">newMenu</span><span class="tok-p">()</span>
<span class="tok-n">submenu2</span><span class="tok-p">.</span><span class="tok-n">appendSection</span><span class="tok-p">(</span><span class="tok-kp">nil</span><span class="tok-p">,</span> <span class="tok-n">section</span><span class="tok-p">)</span>
<span class="tok-n">section</span><span class="tok-p">.</span><span class="tok-n">append</span><span class="tok-p">(</span><span class="tok-s">"left"</span><span class="tok-p">,</span> <span class="tok-s">"win.justify::left"</span><span class="tok-p">)</span>
<span class="tok-n">section</span><span class="tok-p">.</span><span class="tok-n">append</span><span class="tok-p">(</span><span class="tok-s">"center"</span><span class="tok-p">,</span> <span class="tok-s">"win.justify::center"</span><span class="tok-p">)</span>
<span class="tok-n">section</span><span class="tok-p">.</span><span class="tok-n">append</span><span class="tok-p">(</span><span class="tok-s">"right"</span><span class="tok-p">,</span> <span class="tok-s">"win.justify::right"</span><span class="tok-p">)</span>
<span class="tok-k">block</span><span class="tok-p">:</span> <span class="tok-c"># and finally a toggle menu</span>
<span class="tok-k">let</span> <span class="tok-n">subMenu</span> <span class="tok-o">=</span> <span class="tok-n">gio</span><span class="tok-p">.</span><span class="tok-n">newMenu</span><span class="tok-p">()</span>
<span class="tok-n">menu</span><span class="tok-p">.</span><span class="tok-n">appendSubMenu</span><span class="tok-p">(</span><span class="tok-s">"Spelling"</span><span class="tok-p">,</span> <span class="tok-n">submenu</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">section</span> <span class="tok-o">=</span> <span class="tok-n">gio</span><span class="tok-p">.</span><span class="tok-n">newMenu</span><span class="tok-p">()</span>
<span class="tok-n">submenu</span><span class="tok-p">.</span><span class="tok-n">appendSection</span><span class="tok-p">(</span><span class="tok-kp">nil</span><span class="tok-p">,</span> <span class="tok-n">section</span><span class="tok-p">)</span>
<span class="tok-n">section</span><span class="tok-p">.</span><span class="tok-n">append</span><span class="tok-p">(</span><span class="tok-s">"Check"</span><span class="tok-p">,</span> <span class="tok-s">"win.toggleSpellCheck"</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">headerBar</span> <span class="tok-o">=</span> <span class="tok-n">newHeaderBar</span><span class="tok-p">()</span>
<span class="tok-n">headerBar</span><span class="tok-p">.</span><span class="tok-n">setShowCloseButton</span>
<span class="tok-n">headerBar</span><span class="tok-p">.</span><span class="tok-n">setTitle</span><span class="tok-p">(</span><span class="tok-s">"Title"</span><span class="tok-p">)</span>
<span class="tok-n">headerBar</span><span class="tok-p">.</span><span class="tok-n">setSubtitle</span><span class="tok-p">(</span><span class="tok-s">"Subtitle"</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">setTitlebar</span> <span class="tok-p">(</span><span class="tok-n">headerBar</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">menubar</span> <span class="tok-o">=</span> <span class="tok-n">newMenuButton</span><span class="tok-p">()</span>
<span class="tok-c"># menubar.setDirection(ArrowType.none) # show the gears Icon</span>
<span class="tok-c"># let image = newImageFromIconName("open-menu-symbolic", IconSize.menu.ord)</span>
<span class="tok-k">let</span> <span class="tok-n">image</span> <span class="tok-o">=</span> <span class="tok-n">newImageFromIconName</span><span class="tok-p">(</span><span class="tok-s">"document-save"</span><span class="tok-p">,</span> <span class="tok-n">IconSize</span><span class="tok-p">.</span><span class="tok-n">dialog</span><span class="tok-p">.</span><span class="tok-n">ord</span><span class="tok-p">)</span> <span class="tok-c"># dialog is really big!</span>
<span class="tok-n">menubar</span><span class="tok-p">.</span><span class="tok-n">setImage</span><span class="tok-p">(</span><span class="tok-n">image</span><span class="tok-p">)</span> <span class="tok-c"># this is only an example for a custom image</span>
<span class="tok-c"># menubar.setIconName("open-menu-symbolic") # only gtk4</span>
<span class="tok-n">headerBar</span><span class="tok-p">.</span><span class="tok-n">packEnd</span><span class="tok-p">(</span><span class="tok-n">menubar</span><span class="tok-p">)</span>
<span class="tok-n">menubar</span><span class="tok-p">.</span><span class="tok-n">setMenuModel</span><span class="tok-p">(</span><span class="tok-n">menu</span><span class="tok-p">)</span>
<span class="tok-k">block</span><span class="tok-p">:</span> <span class="tok-c"># creat the window related actions</span>
<span class="tok-k">let</span> <span class="tok-n">v</span> <span class="tok-o">=</span> <span class="tok-n">newVariantBoolean</span><span class="tok-p">(</span><span class="tok-kp">true</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">spellCheck</span> <span class="tok-o">=</span> <span class="tok-n">newSimpleActionStateful</span><span class="tok-p">(</span><span class="tok-s">"toggleSpellCheck"</span><span class="tok-p">,</span> <span class="tok-kp">nil</span><span class="tok-p">,</span> <span class="tok-n">v</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">spellCheck</span><span class="tok-p">,</span> <span class="tok-s">"activate"</span><span class="tok-p">,</span> <span class="tok-n">activateToggleAction</span><span class="tok-p">,</span> <span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">actionMap</span><span class="tok-p">.</span><span class="tok-n">addAction</span><span class="tok-p">(</span><span class="tok-n">spellCheck</span><span class="tok-p">)</span>
<span class="tok-k">block</span><span class="tok-p">:</span>
<span class="tok-k">let</span> <span class="tok-n">v</span> <span class="tok-o">=</span> <span class="tok-n">newVariantString</span><span class="tok-p">(</span><span class="tok-s">"left"</span><span class="tok-p">)</span> <span class="tok-c"># default value and</span>
<span class="tok-k">let</span> <span class="tok-n">vt</span> <span class="tok-o">=</span> <span class="tok-n">newVariantType</span><span class="tok-p">(</span><span class="tok-s">"s"</span><span class="tok-p">)</span> <span class="tok-c"># string (value type)</span>
<span class="tok-k">let</span> <span class="tok-n">justifyAction</span> <span class="tok-o">=</span> <span class="tok-n">newSimpleActionStateful</span><span class="tok-p">(</span><span class="tok-s">"justify"</span><span class="tok-p">,</span> <span class="tok-n">vt</span><span class="tok-p">,</span> <span class="tok-n">v</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">justifyAction</span><span class="tok-p">,</span> <span class="tok-s">"activate"</span><span class="tok-p">,</span> <span class="tok-n">activateStatefulAction</span><span class="tok-p">,</span> <span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">actionMap</span><span class="tok-p">.</span><span class="tok-n">addAction</span><span class="tok-p">(</span><span class="tok-n">justifyAction</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">button</span> <span class="tok-o">=</span> <span class="tok-n">newButton</span><span class="tok-p">()</span>
<span class="tok-n">button</span><span class="tok-p">.</span><span class="tok-n">label</span> <span class="tok-o">=</span> <span class="tok-s">"Justify Center"</span>
<span class="tok-n">button</span><span class="tok-p">.</span><span class="tok-n">setDetailedActionName</span><span class="tok-p">(</span><span class="tok-s">"win.justify::center"</span><span class="tok-p">)</span>
<span class="tok-c">#button.setActionName("app.quit") # for a stateless action</span>
<span class="tok-n">setAccelsForAction</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">,</span> <span class="tok-s">"win.justify::right"</span><span class="tok-p">,</span> <span class="tok-s">"<Control><Shift>R"</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">add</span><span class="tok-p">(</span><span class="tok-n">button</span><span class="tok-p">)</span>
<span class="tok-n">showAll</span><span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">main</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">app</span> <span class="tok-o">=</span> <span class="tok-n">newApplication</span><span class="tok-p">(</span><span class="tok-s">"app.example"</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">,</span> <span class="tok-s">"startup"</span><span class="tok-p">,</span> <span class="tok-n">appStartup</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">,</span> <span class="tok-s">"activate"</span><span class="tok-p">,</span> <span class="tok-n">appActivate</span><span class="tok-p">)</span>
<span class="tok-n">echo</span> <span class="tok-s">fmt"GTK Version {majorVersion()}.{minorVersion()}.{microVersion()}"</span>
<span class="tok-k">let</span> <span class="tok-n">status</span> <span class="tok-o">=</span> <span class="tok-n">run</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-n">quit</span><span class="tok-p">(</span><span class="tok-n">status</span><span class="tok-p">)</span>
<span class="tok-n">main</span><span class="tok-p">()</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>While in the previous example we create only a single menu instance in proc appStartup()
for all of our application windows, here we create a new menu for all of our instances
in proc appActivate(). That seems to work fine, so I assume it is correct.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_gsettings">GSettings</h2>
<div class="sectionbody">
<div class="paragraph">
<p>GSettings provides a convenient way to permanently storing configuration data,
and to bind them to properties of widgets.</p>
</div>
<div class="paragraph">
<p>You can read an introduction at <a href="https://blog.gtk.org/2017/05/01/first-steps-with-gsettings/" class="bare">https://blog.gtk.org/2017/05/01/first-steps-with-gsettings/</a>.</p>
</div>
<div class="paragraph">
<p>For using GSettings in our own programs, we have first to create a XML file
which defines names and type of each configuration entry, and additional
provides default value and a description. The file name of such xml files
must always end with ".gschema.xml".
The following example has only one
field called like-nim of type boolean (b). For a real application program
we would install the configuration on our computer — unfortunately we
would need root access for this. We could do it this way:</p>
</div>
<div class="listingblock">
<div class="content">
<pre># For making gsettings available system wide one method is, as root
# https://developer.gnome.org/gio/stable/glib-compile-schemas.html
# echo $XDG_DATA_DIRS
# /usr/share/gnome:/usr/local/share:/usr/share:/usr/share/gdm
# cd /usr/local/share/glib-2.0/schemas
# cp test.gschema.xml .
# glib-compile-schemas .
#</pre>
</div>
</div>
<div class="paragraph">
<p>For testing there is an easier method available:</p>
</div>
<div class="paragraph">
<p>Create a directory and copy the xml file and the test program below into it.</p>
</div>
<div class="paragraph">
<p>Then do, as ordinary user:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>glib-compile-schemas .
nim c gsettings.nim
GSETTINGS_SCHEMA_DIR="." ./gsettings</pre>
</div>
</div>
<div class="paragraph">
<p>This is the xml file and the test program:</p>
</div>
<div id="test.gschema.xml" class="listingblock">
<div class="title">test.gschema.xml</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="xml"><span></span><span class="tok-nt"><schemalist></span>
<span class="tok-nt"><schema</span> <span class="tok-na">path=</span><span class="tok-s">"/org/gnome/recipes/"</span>
<span class="tok-na">id=</span><span class="tok-s">"org.gnome.Recipes"</span><span class="tok-nt">></span>
<span class="tok-nt"><key</span> <span class="tok-na">type=</span><span class="tok-s">"b"</span> <span class="tok-na">name=</span><span class="tok-s">"like-nim"</span><span class="tok-nt">></span>
<span class="tok-nt"><default></span>false<span class="tok-nt"></default></span>
<span class="tok-nt"><summary></span>I like Nim<span class="tok-nt"></summary></span>
<span class="tok-nt"><description></span>
I like or like not
the Nim programming language.
<span class="tok-nt"></description></span>
<span class="tok-nt"></key></span>
<span class="tok-nt"></schema></span>
<span class="tok-nt"></schemalist></span></code></pre>
</div>
</div>
<div id="gsettings.nim" class="listingblock">
<div class="title">gsettings.nim</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="nim"><span></span><span class="tok-c"># gsettings.nim -- basic use of gsettings</span>
<span class="tok-c"># nim c gsettings.nim</span>
<span class="tok-c"># https://blog.gtk.org/2017/05/01/first-steps-with-gsettings/</span>
<span class="tok-c"># https://mail.gnome.org/archives/gtk-list/2016-December/msg00003.html</span>
<span class="tok-kn">import</span> <span class="tok-n">gintro</span><span class="tok-o">/[</span><span class="tok-n">gtk</span><span class="tok-p">,</span> <span class="tok-n">glib</span><span class="tok-p">,</span> <span class="tok-n">gobject</span><span class="tok-p">,</span> <span class="tok-n">gio</span><span class="tok-o">]</span>
<span class="tok-c"># unused</span>
<span class="tok-k">proc </span><span class="tok-nf">toggle</span><span class="tok-p">(</span><span class="tok-n">b</span><span class="tok-p">:</span> <span class="tok-n">CheckButton</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">echo</span> <span class="tok-n">b</span><span class="tok-p">.</span><span class="tok-n">active</span>
<span class="tok-k">let</span> <span class="tok-n">s</span> <span class="tok-o">=</span> <span class="tok-n">newSettings</span><span class="tok-p">(</span><span class="tok-s">"org.gnome.Recipes"</span><span class="tok-p">)</span>
<span class="tok-k">discard</span> <span class="tok-n">s</span><span class="tok-p">.</span><span class="tok-n">setBoolean</span><span class="tok-p">(</span><span class="tok-s">"like-nim"</span><span class="tok-p">,</span> <span class="tok-n">b</span><span class="tok-p">.</span><span class="tok-n">active</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">appActivate</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">:</span> <span class="tok-n">Application</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">window</span> <span class="tok-o">=</span> <span class="tok-n">newApplicationWindow</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">title</span> <span class="tok-o">=</span> <span class="tok-s">"GTK3, Nim and GSettings"</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">defaultSize</span> <span class="tok-o">=</span> <span class="tok-p">(</span><span class="tok-mi">200</span><span class="tok-p">,</span> <span class="tok-mi">200</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">b</span> <span class="tok-o">=</span> <span class="tok-n">newCheckButton</span><span class="tok-p">()</span>
<span class="tok-n">b</span><span class="tok-p">.</span><span class="tok-n">halign</span> <span class="tok-o">=</span> <span class="tok-n">Align</span><span class="tok-p">.</span><span class="tok-n">center</span>
<span class="tok-n">b</span><span class="tok-p">.</span><span class="tok-n">label</span> <span class="tok-o">=</span> <span class="tok-s">"I like Nim"</span>
<span class="tok-c">#b.connect("toggled", toggle) # we don't need this for plain binding!</span>
<span class="tok-k">let</span> <span class="tok-n">s</span> <span class="tok-o">=</span> <span class="tok-n">newSettings</span><span class="tok-p">(</span><span class="tok-s">"org.gnome.Recipes"</span><span class="tok-p">)</span>
<span class="tok-k">if</span> <span class="tok-n">s</span><span class="tok-p">.</span><span class="tok-n">getBoolean</span><span class="tok-p">(</span><span class="tok-s">"like-nim"</span><span class="tok-p">):</span>
<span class="tok-n">echo</span> <span class="tok-s">"I like Nim language"</span>
<span class="tok-p">`</span><span class="tok-k">bind</span><span class="tok-p">`(</span><span class="tok-n">s</span><span class="tok-p">,</span> <span class="tok-s">"like-nim"</span><span class="tok-p">,</span> <span class="tok-n">b</span><span class="tok-p">,</span> <span class="tok-s">"active"</span><span class="tok-p">,</span> <span class="tok-p">{</span><span class="tok-n">SettingsBindFlag</span><span class="tok-p">.</span><span class="tok-n">get</span><span class="tok-p">,</span> <span class="tok-n">SettingsBindFlag</span><span class="tok-p">.</span><span class="tok-kt">set</span><span class="tok-p">})</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">add</span><span class="tok-p">(</span><span class="tok-n">b</span><span class="tok-p">)</span>
<span class="tok-n">showAll</span><span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">main</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">app</span> <span class="tok-o">=</span> <span class="tok-n">newApplication</span><span class="tok-p">(</span><span class="tok-s">"org.gtk.example"</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">,</span> <span class="tok-s">"activate"</span><span class="tok-p">,</span> <span class="tok-n">appActivate</span><span class="tok-p">)</span>
<span class="tok-k">discard</span> <span class="tok-n">run</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-n">main</span><span class="tok-p">()</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>The command "glib-compile-schemas ." compiles all schemas in the current directory. And
"GSETTINGS_SCHEMA_DIR="." ./gsettings" launches our test program with the environment
variable GSETTINGS_SCHEMA_DIR pointing to the current directory, containing the compiled schema.</p>
</div>
<div class="paragraph">
<p>Note that a system tool with same name as our test program exists — that one can be used
to get or set configuration data — for example you may query the current state of field
"like-nim" with</p>
</div>
<div class="listingblock">
<div class="content">
<pre>gsettings --schemadir "." get org.gnome.Recipes like-nim</pre>
</div>
</div>
<div class="paragraph">
<p>Or test program first creates a window with a check button. Then our settings file is
opened and we print the current value of the boolean variable. After that the
bind procedure binds the active property (checkmark state) of our widget to the
"like-nim" entry of our settings file. The result of this binding is, that
our checkmark state is automatically made persistent, that is when we terminate
and restart our test program, the checkmark will have the last state again.</p>
</div>
<div class="paragraph">
<p>These bindings works for booleans, integers, floats, strings. The type of the property of the
widget must be identical with the corresponding type of the entry in the settings xml file.</p>
</div>
<div class="paragraph">
<p>On Linux you may permanently set the gsetting directory by adding the statement</p>
</div>
<div class="listingblock">
<div class="content">
<pre>export GSETTINGS_SCHEMA_DIR="pathToMyProg"</pre>
</div>
</div>
<div class="paragraph">
<p>to your .bashrc file — of course after replacing pathToMyProg with the actual path.</p>
</div>
<div class="paragraph">
<p>For more informations about gsettings see</p>
</div>
<div class="paragraph">
<p><a href="https://developer.gnome.org/gio/stable/GSettings.html" class="bare">https://developer.gnome.org/gio/stable/GSettings.html</a>.</p>
</div>
<div class="paragraph">
<p><a href="https://developer.gnome.org/gio/stable/running-gio-apps.html" class="bare">https://developer.gnome.org/gio/stable/running-gio-apps.html</a></p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_drawing_with_cairo_graphics_library">Drawing with Cairo graphics library</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The next example shows how we can use the cairo graphics library for drawing on a DrawingArea widget,
and at the same time uses glib timeoutAdd() function to create a timer which periodically calls the
drawing function to create some animations. The code is based on a recent post to the cairo mailing list
and shows a sine wave which is continuously moving to the left.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
The gobject-introspection generated cairo module was only a minimal stub, because cairo
library does not really support introspection. Now we are using a cairo module which is generated
directly from the cairo C header files with the tool c2nim and then modified to support a high level
API.
</td>
</tr>
</table>
</div>
<div id="cairo_anim.nim" class="listingblock">
<div class="title">cairo_anim.nim</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="nim"><span></span><span class="tok-c"># https://lists.cairographics.org/archives/cairo/2016-October/027791.html</span>
<span class="tok-c"># Nim version of that plain cairo animation example</span>
<span class="tok-kn">import</span> <span class="tok-n">gintro</span><span class="tok-o">/[</span><span class="tok-n">gtk</span><span class="tok-p">,</span> <span class="tok-n">glib</span><span class="tok-p">,</span> <span class="tok-n">gobject</span><span class="tok-p">,</span> <span class="tok-n">gio</span><span class="tok-p">,</span> <span class="tok-n">cairo</span><span class="tok-o">]</span>
<span class="tok-kn">import</span> <span class="tok-n">math</span>
<span class="tok-k">const</span>
<span class="tok-n">NumPoints</span> <span class="tok-o">=</span> <span class="tok-mi">1000</span>
<span class="tok-n">Period</span> <span class="tok-o">=</span> <span class="tok-mf">100.0</span>
<span class="tok-k">proc </span><span class="tok-nf">invalidateCb</span><span class="tok-p">(</span><span class="tok-n">w</span><span class="tok-p">:</span> <span class="tok-n">Widget</span><span class="tok-p">):</span> <span class="tok-kt">bool</span> <span class="tok-o">=</span>
<span class="tok-n">queueDraw</span><span class="tok-p">(</span><span class="tok-n">w</span><span class="tok-p">)</span>
<span class="tok-k">return</span> <span class="tok-n">SOURCE_CONTINUE</span>
<span class="tok-k">proc </span><span class="tok-nf">sineToPoint</span><span class="tok-p">(</span><span class="tok-n">x</span><span class="tok-p">,</span> <span class="tok-n">width</span><span class="tok-p">,</span> <span class="tok-n">height</span><span class="tok-p">:</span> <span class="tok-kt">int</span><span class="tok-p">):</span> <span class="tok-kt">float</span> <span class="tok-o">=</span>
<span class="tok-n">math</span><span class="tok-p">.</span><span class="tok-n">sin</span><span class="tok-p">(</span><span class="tok-n">x</span><span class="tok-p">.</span><span class="tok-kt">float</span> <span class="tok-o">*</span> <span class="tok-n">math</span><span class="tok-p">.</span><span class="tok-n">TAU</span> <span class="tok-o">/</span> <span class="tok-n">Period</span><span class="tok-p">)</span> <span class="tok-o">*</span> <span class="tok-n">height</span><span class="tok-p">.</span><span class="tok-kt">float</span> <span class="tok-o">*</span> <span class="tok-mf">0.5</span> <span class="tok-o">+</span> <span class="tok-n">height</span><span class="tok-p">.</span><span class="tok-kt">float</span> <span class="tok-o">*</span> <span class="tok-mf">0.5</span>
<span class="tok-k">proc </span><span class="tok-nf">drawingAreaDrawCb</span><span class="tok-p">(</span><span class="tok-n">widget</span><span class="tok-p">:</span> <span class="tok-n">DrawingArea</span><span class="tok-p">;</span> <span class="tok-n">context</span><span class="tok-p">:</span> <span class="tok-n">Context</span><span class="tok-p">):</span> <span class="tok-kt">bool</span> <span class="tok-o">=</span>
<span class="tok-kd">var</span> <span class="tok-n">redrawNumber</span> <span class="tok-p">{.</span><span class="tok-n">global</span><span class="tok-p">.}</span> <span class="tok-p">:</span> <span class="tok-kt">int</span>
<span class="tok-k">let</span> <span class="tok-n">width</span> <span class="tok-o">=</span> <span class="tok-n">getAllocatedWidth</span><span class="tok-p">(</span><span class="tok-n">widget</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">height</span> <span class="tok-o">=</span> <span class="tok-n">getAllocatedHeight</span><span class="tok-p">(</span><span class="tok-n">widget</span><span class="tok-p">)</span>
<span class="tok-k">for</span> <span class="tok-n">i</span> <span class="tok-ow">in</span> <span class="tok-mi">1</span> <span class="tok-p">..</span><span class="tok-o"><</span> <span class="tok-n">NumPoints</span><span class="tok-p">:</span>
<span class="tok-n">context</span><span class="tok-p">.</span><span class="tok-n">lineTo</span><span class="tok-p">(</span><span class="tok-n">i</span><span class="tok-p">.</span><span class="tok-kt">float</span> <span class="tok-p">,</span> <span class="tok-n">sineToPoint</span><span class="tok-p">(</span><span class="tok-n">i</span> <span class="tok-o">+</span> <span class="tok-n">redrawNumber</span><span class="tok-p">,</span> <span class="tok-n">width</span><span class="tok-p">,</span> <span class="tok-n">height</span><span class="tok-p">))</span>
<span class="tok-n">context</span><span class="tok-p">.</span><span class="tok-n">stroke</span>
<span class="tok-n">inc</span><span class="tok-p">(</span><span class="tok-n">redrawNumber</span><span class="tok-p">)</span>
<span class="tok-k">return</span> <span class="tok-kp">true</span> <span class="tok-c"># TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.</span>
<span class="tok-k">proc </span><span class="tok-nf">appActivate</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">:</span> <span class="tok-n">Application</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">window</span> <span class="tok-o">=</span> <span class="tok-n">newApplicationWindow</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">title</span> <span class="tok-o">=</span> <span class="tok-s">"Drawing example"</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">defaultSize</span> <span class="tok-o">=</span> <span class="tok-p">(</span><span class="tok-mi">400</span><span class="tok-p">,</span> <span class="tok-mi">400</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">drawingArea</span> <span class="tok-o">=</span> <span class="tok-n">newDrawingArea</span><span class="tok-p">()</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">add</span><span class="tok-p">(</span><span class="tok-n">drawingArea</span><span class="tok-p">)</span>
<span class="tok-n">showAll</span><span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">)</span>
<span class="tok-k">discard</span> <span class="tok-n">timeoutAdd</span><span class="tok-p">(</span><span class="tok-mi">1000</span> <span class="tok-ow">div</span> <span class="tok-mi">60</span><span class="tok-p">,</span> <span class="tok-n">invalidateCb</span><span class="tok-p">,</span> <span class="tok-n">drawingArea</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">drawingArea</span><span class="tok-p">,</span> <span class="tok-s">"draw"</span><span class="tok-p">,</span> <span class="tok-n">drawingAreaDrawCb</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">main</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">app</span> <span class="tok-o">=</span> <span class="tok-n">newApplication</span><span class="tok-p">(</span><span class="tok-s">"org.gtk.example"</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">,</span> <span class="tok-s">"activate"</span><span class="tok-p">,</span> <span class="tok-n">appActivate</span><span class="tok-p">)</span>
<span class="tok-k">discard</span> <span class="tok-n">run</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-n">main</span><span class="tok-p">()</span></code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_a_simple_listview_example">A simple ListView example</h2>
<div class="sectionbody">
<div class="imageblock">
<div class="content">
<img src="http://ssalewski.de/tmp/NimGTK3ListView.png" alt="NimGTK3ListView">
</div>
</div>
<div class="paragraph">
<p>Recently someone reported about some problems porting a GTK2 application to Nim GTK3, so I will give a small example
which may help using ListViews and TreeViews. These two widget types are the most complicated widget types in GTK — I can remember that I had some trouble myself when I used Ruby-GTK some years ago. As I can currently not remember
details about use of ListView widgets, I decided to take an example code from <a href="http://zetcode.com/gui/gtk2/gtktreeview/">zetcode.com</a> as starting point. Of course
porting is straight forward, but when I tried to compile the result I noticed some bugs and restrictions of current
gintro package. Of course not really surprising, as the package is not really tested yet. I will try to fix these bugs later.
First problem is, that we store a ListStore as model in our TreeView, and we need to extract that ListStore from the TreeView
for some operations. But module gtk.nim offers currently only a function to extract the model itself, which is of type TreeModel.
In the C code an upcast is used to get the ListStore from the retrieved TreeModel. To avoid casting in our Nim code, I have just copied
the getModel() proc and modified it to return a ListStore. Second problem was, that module gio export a ListStore datatype also.
To avoid prefixing all ListStore types with gtk prefix, I excluded gio.ListStore from import list. And finally a real bug:
Proc newListStore() expects currently a plain pointer as last parameter, while we know that it should be the address of a list of GTypes.
So we have to use an ugly cast for now. For populating the ListStore currently GValues are used. That is not very convenient, and
for that we need the correct GType of our string list. In C one would use the macro G_TYPE_STRING, which is not provided by
gobject-introspection. So we use typeFromName() to get the correct GType, which works fine when we know that the string name is "gchararray".
Later we will provide a higher level function for this process.</p>
</div>
<div class="paragraph">
<p>I will try to give more and better explained ListView and TreeView examples later…​</p>
</div>
<div id="listview.nim" class="listingblock">
<div class="title">listview.nim</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="nim"><span></span><span class="tok-c"># http://zetcode.com/gui/gtk2/gtktreeview/</span>
<span class="tok-c"># dynamiclistview.c</span>
<span class="tok-kn">import</span> <span class="tok-n">gintro</span><span class="tok-o">/[</span><span class="tok-n">glib</span><span class="tok-p">,</span> <span class="tok-n">gobject</span><span class="tok-p">,</span> <span class="tok-n">gtk</span><span class="tok-o">]</span>
<span class="tok-kn">import</span> <span class="tok-n">gintro</span><span class="tok-o">/</span><span class="tok-n">gio</span> <span class="tok-k">except</span> <span class="tok-n">ListStore</span>
<span class="tok-k">const</span>
<span class="tok-n">LIST_ITEM</span> <span class="tok-o">=</span> <span class="tok-mi">0</span>
<span class="tok-n">N_COLUMNS</span> <span class="tok-o">=</span> <span class="tok-mi">1</span>
<span class="tok-kd">var</span> <span class="tok-n">list</span><span class="tok-p">:</span> <span class="tok-n">TreeView</span>
<span class="tok-c"># this is copied from gtk.nim</span>
<span class="tok-c">#proc getModel*(self: TreeView): TreeModel =</span>
<span class="tok-c"># new(result)</span>
<span class="tok-c"># result.impl = gtk_tree_view_get_model(cast[ptr TreeView00](self.impl))</span>
<span class="tok-k">proc </span><span class="tok-nf">getListStore</span><span class="tok-p">(</span><span class="tok-n">self</span><span class="tok-p">:</span> <span class="tok-n">TreeView</span><span class="tok-p">):</span> <span class="tok-n">ListStore</span> <span class="tok-o">=</span>
<span class="tok-n">new</span><span class="tok-p">(</span><span class="tok-n">result</span><span class="tok-p">)</span>
<span class="tok-n">result</span><span class="tok-p">.</span><span class="tok-n">impl</span> <span class="tok-o">=</span> <span class="tok-n">gtk_tree_view_get_model</span><span class="tok-p">(</span><span class="tok-k">cast</span><span class="tok-o">[</span><span class="tok-k">ptr</span> <span class="tok-n">TreeView00</span><span class="tok-o">]</span><span class="tok-p">(</span><span class="tok-n">self</span><span class="tok-p">.</span><span class="tok-n">impl</span><span class="tok-p">))</span>
<span class="tok-k">proc </span><span class="tok-nf">appendItem</span><span class="tok-p">(</span><span class="tok-n">widget</span><span class="tok-p">:</span> <span class="tok-n">Button</span><span class="tok-p">;</span> <span class="tok-n">entry</span><span class="tok-p">:</span> <span class="tok-n">Entry</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-kd">var</span>
<span class="tok-n">val</span><span class="tok-p">:</span> <span class="tok-n">Value</span>
<span class="tok-n">iter</span><span class="tok-p">:</span> <span class="tok-n">TreeIter</span>
<span class="tok-k">let</span> <span class="tok-n">store</span> <span class="tok-o">=</span> <span class="tok-n">getListStore</span><span class="tok-p">(</span><span class="tok-n">list</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">gtype</span> <span class="tok-o">=</span> <span class="tok-n">typeFromName</span><span class="tok-p">(</span><span class="tok-s">"gchararray"</span><span class="tok-p">)</span>
<span class="tok-k">discard</span> <span class="tok-n">gValueInit</span><span class="tok-p">(</span><span class="tok-n">val</span><span class="tok-p">,</span> <span class="tok-n">gtype</span><span class="tok-p">)</span>
<span class="tok-n">gValueSetString</span><span class="tok-p">(</span><span class="tok-n">val</span><span class="tok-p">,</span> <span class="tok-n">entry</span><span class="tok-p">.</span><span class="tok-n">text</span><span class="tok-p">)</span>
<span class="tok-n">store</span><span class="tok-p">.</span><span class="tok-n">append</span><span class="tok-p">(</span><span class="tok-n">iter</span><span class="tok-p">)</span>
<span class="tok-n">store</span><span class="tok-p">.</span><span class="tok-n">setValue</span><span class="tok-p">(</span><span class="tok-n">iter</span><span class="tok-p">,</span> <span class="tok-n">LIST_ITEM</span><span class="tok-p">,</span> <span class="tok-n">val</span><span class="tok-p">)</span>
<span class="tok-n">entry</span><span class="tok-p">.</span><span class="tok-n">text</span> <span class="tok-o">=</span> <span class="tok-s">""</span>
<span class="tok-k">proc </span><span class="tok-nf">removeItem</span><span class="tok-p">(</span><span class="tok-n">widget</span><span class="tok-p">:</span> <span class="tok-n">Button</span><span class="tok-p">;</span> <span class="tok-n">selection</span><span class="tok-p">:</span> <span class="tok-n">TreeSelection</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-kd">var</span>
<span class="tok-n">ls</span><span class="tok-p">:</span> <span class="tok-n">ListStore</span>
<span class="tok-n">iter</span><span class="tok-p">:</span> <span class="tok-n">TreeIter</span>
<span class="tok-k">let</span> <span class="tok-n">store</span> <span class="tok-o">=</span> <span class="tok-n">getListStore</span><span class="tok-p">(</span><span class="tok-n">list</span><span class="tok-p">)</span>
<span class="tok-k">if</span> <span class="tok-ow">not</span> <span class="tok-n">store</span><span class="tok-p">.</span><span class="tok-n">getIterFirst</span><span class="tok-p">(</span><span class="tok-n">iter</span><span class="tok-p">):</span>
<span class="tok-k">return</span>
<span class="tok-k">if</span> <span class="tok-n">getSelected</span><span class="tok-p">(</span><span class="tok-n">selection</span><span class="tok-p">,</span> <span class="tok-n">ls</span><span class="tok-p">,</span> <span class="tok-n">iter</span><span class="tok-p">):</span>
<span class="tok-k">discard</span> <span class="tok-n">store</span><span class="tok-p">.</span><span class="tok-n">remove</span><span class="tok-p">(</span><span class="tok-n">iter</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">onRemoveAll</span><span class="tok-p">(</span><span class="tok-n">widget</span><span class="tok-p">:</span> <span class="tok-n">Button</span><span class="tok-p">;</span> <span class="tok-n">selection</span><span class="tok-p">:</span> <span class="tok-n">TreeSelection</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-kd">var</span>
<span class="tok-n">iter</span><span class="tok-p">:</span> <span class="tok-n">TreeIter</span>
<span class="tok-k">let</span> <span class="tok-n">store</span> <span class="tok-o">=</span> <span class="tok-n">getListStore</span><span class="tok-p">(</span><span class="tok-n">list</span><span class="tok-p">)</span>
<span class="tok-k">if</span> <span class="tok-ow">not</span> <span class="tok-n">store</span><span class="tok-p">.</span><span class="tok-n">getIterFirst</span><span class="tok-p">(</span><span class="tok-n">iter</span><span class="tok-p">):</span>
<span class="tok-k">return</span>
<span class="tok-n">clear</span><span class="tok-p">(</span><span class="tok-n">store</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">initList</span><span class="tok-p">(</span><span class="tok-n">list</span><span class="tok-p">:</span> <span class="tok-n">TreeView</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">renderer</span> <span class="tok-o">=</span> <span class="tok-n">newCellRendererText</span><span class="tok-p">()</span>
<span class="tok-k">let</span> <span class="tok-n">column</span> <span class="tok-o">=</span> <span class="tok-n">newTreeViewColumn</span><span class="tok-p">()</span>
<span class="tok-n">column</span><span class="tok-p">.</span><span class="tok-n">title</span> <span class="tok-o">=</span> <span class="tok-s">"List Item"</span>
<span class="tok-n">column</span><span class="tok-p">.</span><span class="tok-n">packStart</span><span class="tok-p">(</span><span class="tok-n">renderer</span><span class="tok-p">,</span> <span class="tok-kp">true</span><span class="tok-p">)</span>
<span class="tok-n">column</span><span class="tok-p">.</span><span class="tok-n">addAttribute</span><span class="tok-p">(</span><span class="tok-n">renderer</span><span class="tok-p">,</span> <span class="tok-s">"text"</span><span class="tok-p">,</span> <span class="tok-n">LIST_ITEM</span><span class="tok-p">)</span>
<span class="tok-k">discard</span> <span class="tok-n">list</span><span class="tok-p">.</span><span class="tok-n">appendColumn</span><span class="tok-p">(</span><span class="tok-n">column</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">gtype</span> <span class="tok-o">=</span> <span class="tok-n">typeFromName</span><span class="tok-p">(</span><span class="tok-s">"gchararray"</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">store</span> <span class="tok-o">=</span> <span class="tok-n">newListStore</span><span class="tok-p">(</span><span class="tok-n">N_COLUMNS</span><span class="tok-p">,</span> <span class="tok-k">cast</span><span class="tok-o">[</span><span class="tok-n">pointer</span><span class="tok-o">]</span><span class="tok-p">(</span> <span class="tok-n">unsafeaddr</span> <span class="tok-n">gtype</span><span class="tok-p">))</span> <span class="tok-c"># cast due to bug in gtk.nim</span>
<span class="tok-n">list</span><span class="tok-p">.</span><span class="tok-n">setModel</span><span class="tok-p">(</span><span class="tok-n">store</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">appActivate</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">:</span> <span class="tok-n">Application</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-k">let</span>
<span class="tok-n">window</span> <span class="tok-o">=</span> <span class="tok-n">newApplicationWindow</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-n">sw</span> <span class="tok-o">=</span> <span class="tok-n">newScrolledWindow</span><span class="tok-p">()</span>
<span class="tok-n">hbox</span> <span class="tok-o">=</span> <span class="tok-n">newBox</span><span class="tok-p">(</span><span class="tok-n">Orientation</span><span class="tok-p">.</span><span class="tok-n">horizontal</span><span class="tok-p">,</span> <span class="tok-mi">5</span><span class="tok-p">)</span>
<span class="tok-n">vbox</span> <span class="tok-o">=</span> <span class="tok-n">newBox</span><span class="tok-p">(</span><span class="tok-n">Orientation</span><span class="tok-p">.</span><span class="tok-n">vertical</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">)</span>
<span class="tok-n">add</span> <span class="tok-o">=</span> <span class="tok-n">newButton</span><span class="tok-p">(</span><span class="tok-s">"Add"</span><span class="tok-p">)</span>
<span class="tok-n">remove</span> <span class="tok-o">=</span> <span class="tok-n">newButton</span><span class="tok-p">(</span><span class="tok-s">"Remove"</span><span class="tok-p">)</span>
<span class="tok-n">removeAll</span> <span class="tok-o">=</span> <span class="tok-n">newButton</span><span class="tok-p">(</span><span class="tok-s">"Remove All"</span><span class="tok-p">)</span>
<span class="tok-n">entry</span> <span class="tok-o">=</span> <span class="tok-n">newEntry</span><span class="tok-p">()</span>
<span class="tok-n">window</span><span class="tok-p">.</span> <span class="tok-n">title</span> <span class="tok-o">=</span> <span class="tok-s">"List view"</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">position</span> <span class="tok-o">=</span> <span class="tok-n">WindowPosition</span><span class="tok-p">.</span><span class="tok-n">center</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">borderWidth</span> <span class="tok-o">=</span> <span class="tok-mi">10</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">setSizeRequest</span><span class="tok-p">(</span><span class="tok-mi">370</span><span class="tok-p">,</span> <span class="tok-mi">270</span><span class="tok-p">)</span>
<span class="tok-n">list</span> <span class="tok-o">=</span> <span class="tok-n">newTreeView</span><span class="tok-p">()</span>
<span class="tok-n">sw</span><span class="tok-p">.</span><span class="tok-n">add</span><span class="tok-p">(</span><span class="tok-n">list</span><span class="tok-p">)</span>
<span class="tok-n">sw</span><span class="tok-p">.</span><span class="tok-n">setPolicy</span><span class="tok-p">(</span><span class="tok-n">PolicyType</span><span class="tok-p">.</span><span class="tok-n">automatic</span><span class="tok-p">,</span> <span class="tok-n">PolicyType</span><span class="tok-p">.</span><span class="tok-n">automatic</span><span class="tok-p">)</span>
<span class="tok-n">sw</span><span class="tok-p">.</span><span class="tok-n">setShadowType</span><span class="tok-p">(</span><span class="tok-n">ShadowType</span><span class="tok-p">.</span><span class="tok-n">etchedIn</span><span class="tok-p">)</span>
<span class="tok-n">list</span><span class="tok-p">.</span><span class="tok-n">setHeadersVisible</span><span class="tok-p">(</span><span class="tok-kp">false</span><span class="tok-p">)</span>
<span class="tok-n">vbox</span><span class="tok-p">.</span><span class="tok-n">packStart</span><span class="tok-p">(</span><span class="tok-n">sw</span><span class="tok-p">,</span> <span class="tok-kp">true</span><span class="tok-p">,</span> <span class="tok-kp">true</span><span class="tok-p">,</span> <span class="tok-mi">5</span><span class="tok-p">)</span>
<span class="tok-n">entry</span><span class="tok-p">.</span><span class="tok-n">setSizeRequest</span><span class="tok-p">(</span><span class="tok-mi">120</span><span class="tok-p">,</span> <span class="tok-o">-</span><span class="tok-mi">1</span><span class="tok-p">)</span>
<span class="tok-n">hbox</span><span class="tok-p">.</span><span class="tok-n">packStart</span><span class="tok-p">(</span><span class="tok-n">add</span><span class="tok-p">,</span> <span class="tok-kp">false</span><span class="tok-p">,</span> <span class="tok-kp">true</span><span class="tok-p">,</span> <span class="tok-mi">3</span><span class="tok-p">)</span>
<span class="tok-n">hbox</span><span class="tok-p">.</span><span class="tok-n">packStart</span><span class="tok-p">(</span><span class="tok-n">entry</span><span class="tok-p">,</span> <span class="tok-kp">false</span><span class="tok-p">,</span> <span class="tok-kp">true</span><span class="tok-p">,</span> <span class="tok-mi">3</span><span class="tok-p">)</span>
<span class="tok-n">hbox</span><span class="tok-p">.</span><span class="tok-n">packStart</span><span class="tok-p">(</span><span class="tok-n">remove</span><span class="tok-p">,</span> <span class="tok-kp">false</span><span class="tok-p">,</span> <span class="tok-kp">true</span><span class="tok-p">,</span> <span class="tok-mi">3</span><span class="tok-p">)</span>
<span class="tok-n">hbox</span><span class="tok-p">.</span><span class="tok-n">packStart</span><span class="tok-p">(</span><span class="tok-n">removeAll</span><span class="tok-p">,</span> <span class="tok-kp">false</span><span class="tok-p">,</span> <span class="tok-kp">true</span><span class="tok-p">,</span> <span class="tok-mi">3</span><span class="tok-p">)</span>
<span class="tok-n">vbox</span><span class="tok-p">.</span><span class="tok-n">packStart</span><span class="tok-p">(</span><span class="tok-n">hbox</span><span class="tok-p">,</span> <span class="tok-kp">false</span><span class="tok-p">,</span> <span class="tok-kp">true</span><span class="tok-p">,</span> <span class="tok-mi">3</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">add</span><span class="tok-p">(</span><span class="tok-n">vbox</span><span class="tok-p">)</span>
<span class="tok-n">initList</span><span class="tok-p">(</span><span class="tok-n">list</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">selection</span> <span class="tok-o">=</span> <span class="tok-n">getSelection</span><span class="tok-p">(</span><span class="tok-n">list</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">add</span><span class="tok-p">,</span> <span class="tok-s">"clicked"</span><span class="tok-p">,</span> <span class="tok-n">listview</span><span class="tok-p">.</span><span class="tok-n">appendItem</span><span class="tok-p">,</span> <span class="tok-n">entry</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">remove</span><span class="tok-p">,</span> <span class="tok-s">"clicked"</span><span class="tok-p">,</span> <span class="tok-n">listview</span><span class="tok-p">.</span><span class="tok-n">removeItem</span><span class="tok-p">,</span> <span class="tok-n">selection</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">removeAll</span><span class="tok-p">,</span> <span class="tok-s">"clicked"</span><span class="tok-p">,</span> <span class="tok-n">listview</span><span class="tok-p">.</span><span class="tok-n">onRemoveAll</span><span class="tok-p">,</span> <span class="tok-n">selection</span><span class="tok-p">)</span>
<span class="tok-n">showAll</span><span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">main</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">app</span> <span class="tok-o">=</span> <span class="tok-n">newApplication</span><span class="tok-p">(</span><span class="tok-s">"org.gtk.example"</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">,</span> <span class="tok-s">"activate"</span><span class="tok-p">,</span> <span class="tok-n">appActivate</span><span class="tok-p">)</span>
<span class="tok-k">discard</span> <span class="tok-n">run</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-n">main</span><span class="tok-p">()</span></code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_a_listview_example_with_css_styling">A ListView example with CSS styling</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Recently C. Eric Cashon provided this example at <a href="https://discourse.gnome.org/t/gtk-treeview-cell-color-change/1750/3" class="bare">https://discourse.gnome.org/t/gtk-treeview-cell-color-change/1750/3</a></p>
</div>
<div class="paragraph">
<p>I will show his original code here too, so we can compare it better with the Nim version.
We see that Nim code has currently some disadvantages still, for example we have no
varargs procs implemented, so setting of properties and attributes is done using GValues,
which is typesafe, but not really compact. That is not too bad, but we may consider
creating macros to support a more dense, but still typesafe way similar to C’s varargs functions.</p>
</div>
<div id="cell_color1.c" class="listingblock">
<div class="title">cell_color1.c</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="c"><span></span><span class="tok-c1">// gcc -Wall cell_color1.c -o cell_color1 `pkg-config --cflags --libs gtk+-3.0`</span>
<span class="tok-c1">// https://discourse.gnome.org/t/gtk-treeview-cell-color-change/1750/4</span>
<span class="tok-c1">// C. Eric Cashon</span>
<span class="tok-cp">#include</span><span class="tok-cpf"><gtk/gtk.h></span><span class="tok-cp"></span>
<span class="tok-k">enum</span>
<span class="tok-p">{</span>
<span class="tok-n">ID</span><span class="tok-p">,</span>
<span class="tok-n">PROGRAM</span><span class="tok-p">,</span>
<span class="tok-n">COLOR1</span><span class="tok-p">,</span>
<span class="tok-n">COLOR2</span><span class="tok-p">,</span>
<span class="tok-n">COLUMNS</span>
<span class="tok-p">};</span>
<span class="tok-kt">int</span> <span class="tok-nf">main</span><span class="tok-p">(</span><span class="tok-kt">int</span> <span class="tok-n">argc</span><span class="tok-p">,</span> <span class="tok-kt">char</span> <span class="tok-o">*</span><span class="tok-n">argv</span><span class="tok-p">[])</span>
<span class="tok-p">{</span>
<span class="tok-n">gtk_init</span><span class="tok-p">(</span><span class="tok-o">&</span><span class="tok-n">argc</span><span class="tok-p">,</span> <span class="tok-o">&</span><span class="tok-n">argv</span><span class="tok-p">);</span>
<span class="tok-n">GtkWidget</span> <span class="tok-o">*</span><span class="tok-n">window</span><span class="tok-o">=</span><span class="tok-n">gtk_window_new</span><span class="tok-p">(</span><span class="tok-n">GTK_WINDOW_TOPLEVEL</span><span class="tok-p">);</span>
<span class="tok-n">gtk_window_set_title</span><span class="tok-p">(</span><span class="tok-n">GTK_WINDOW</span><span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">),</span> <span class="tok-s">"Select Cell"</span><span class="tok-p">);</span>
<span class="tok-n">gtk_window_set_position</span><span class="tok-p">(</span><span class="tok-n">GTK_WINDOW</span><span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">),</span> <span class="tok-n">GTK_WIN_POS_CENTER</span><span class="tok-p">);</span>
<span class="tok-n">gtk_window_set_default_size</span><span class="tok-p">(</span><span class="tok-n">GTK_WINDOW</span><span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">),</span> <span class="tok-mi">500</span><span class="tok-p">,</span> <span class="tok-mi">500</span><span class="tok-p">);</span>
<span class="tok-n">gtk_container_set_border_width</span><span class="tok-p">(</span><span class="tok-n">GTK_CONTAINER</span><span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">),</span> <span class="tok-mi">20</span><span class="tok-p">);</span>
<span class="tok-n">g_signal_connect</span><span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">,</span> <span class="tok-s">"destroy"</span><span class="tok-p">,</span> <span class="tok-n">G_CALLBACK</span><span class="tok-p">(</span><span class="tok-n">gtk_main_quit</span><span class="tok-p">),</span> <span class="tok-nb">NULL</span><span class="tok-p">);</span>
<span class="tok-n">GtkTreeIter</span> <span class="tok-n">iter</span><span class="tok-p">;</span>
<span class="tok-n">GtkListStore</span> <span class="tok-o">*</span><span class="tok-n">store</span><span class="tok-o">=</span><span class="tok-n">gtk_list_store_new</span><span class="tok-p">(</span><span class="tok-n">COLUMNS</span><span class="tok-p">,</span> <span class="tok-n">G_TYPE_UINT</span><span class="tok-p">,</span> <span class="tok-n">G_TYPE_STRING</span><span class="tok-p">,</span> <span class="tok-n">G_TYPE_STRING</span><span class="tok-p">,</span> <span class="tok-n">G_TYPE_STRING</span><span class="tok-p">);</span>
<span class="tok-n">gtk_list_store_append</span><span class="tok-p">(</span><span class="tok-n">store</span><span class="tok-p">,</span> <span class="tok-o">&</span><span class="tok-n">iter</span><span class="tok-p">);</span>
<span class="tok-n">gtk_list_store_set</span><span class="tok-p">(</span><span class="tok-n">store</span><span class="tok-p">,</span> <span class="tok-o">&</span><span class="tok-n">iter</span><span class="tok-p">,</span> <span class="tok-n">ID</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-n">PROGRAM</span><span class="tok-p">,</span> <span class="tok-s">"Gedit"</span><span class="tok-p">,</span> <span class="tok-n">COLOR1</span><span class="tok-p">,</span> <span class="tok-s">"DarkCyan"</span><span class="tok-p">,</span> <span class="tok-n">COLOR2</span><span class="tok-p">,</span> <span class="tok-s">"cyan"</span><span class="tok-p">,</span> <span class="tok-o">-</span><span class="tok-mi">1</span><span class="tok-p">);</span>
<span class="tok-n">gtk_list_store_append</span><span class="tok-p">(</span><span class="tok-n">store</span><span class="tok-p">,</span> <span class="tok-o">&</span><span class="tok-n">iter</span><span class="tok-p">);</span>
<span class="tok-n">gtk_list_store_set</span><span class="tok-p">(</span><span class="tok-n">store</span><span class="tok-p">,</span> <span class="tok-o">&</span><span class="tok-n">iter</span><span class="tok-p">,</span> <span class="tok-n">ID</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-n">PROGRAM</span><span class="tok-p">,</span> <span class="tok-s">"Gimp"</span><span class="tok-p">,</span> <span class="tok-n">COLOR1</span><span class="tok-p">,</span> <span class="tok-s">"LightSlateGray"</span><span class="tok-p">,</span> <span class="tok-n">COLOR2</span><span class="tok-p">,</span> <span class="tok-s">"cyan"</span><span class="tok-p">,</span> <span class="tok-o">-</span><span class="tok-mi">1</span><span class="tok-p">);</span>
<span class="tok-n">gtk_list_store_append</span><span class="tok-p">(</span><span class="tok-n">store</span><span class="tok-p">,</span> <span class="tok-o">&</span><span class="tok-n">iter</span><span class="tok-p">);</span>
<span class="tok-n">gtk_list_store_set</span><span class="tok-p">(</span><span class="tok-n">store</span><span class="tok-p">,</span> <span class="tok-o">&</span><span class="tok-n">iter</span><span class="tok-p">,</span> <span class="tok-n">ID</span><span class="tok-p">,</span> <span class="tok-mi">2</span><span class="tok-p">,</span> <span class="tok-n">PROGRAM</span><span class="tok-p">,</span> <span class="tok-s">"Inkscape"</span><span class="tok-p">,</span> <span class="tok-n">COLOR1</span><span class="tok-p">,</span> <span class="tok-s">"DarkCyan"</span><span class="tok-p">,</span> <span class="tok-n">COLOR2</span><span class="tok-p">,</span> <span class="tok-s">"cyan"</span><span class="tok-p">,</span> <span class="tok-o">-</span><span class="tok-mi">1</span><span class="tok-p">);</span>
<span class="tok-n">gtk_list_store_append</span><span class="tok-p">(</span><span class="tok-n">store</span><span class="tok-p">,</span> <span class="tok-o">&</span><span class="tok-n">iter</span><span class="tok-p">);</span>
<span class="tok-n">gtk_list_store_set</span><span class="tok-p">(</span><span class="tok-n">store</span><span class="tok-p">,</span> <span class="tok-o">&</span><span class="tok-n">iter</span><span class="tok-p">,</span> <span class="tok-n">ID</span><span class="tok-p">,</span> <span class="tok-mi">3</span><span class="tok-p">,</span> <span class="tok-n">PROGRAM</span><span class="tok-p">,</span> <span class="tok-s">"Firefox"</span><span class="tok-p">,</span> <span class="tok-n">COLOR1</span><span class="tok-p">,</span> <span class="tok-s">"LightSlateGray"</span><span class="tok-p">,</span> <span class="tok-n">COLOR2</span><span class="tok-p">,</span> <span class="tok-s">"cyan"</span><span class="tok-p">,</span> <span class="tok-o">-</span><span class="tok-mi">1</span><span class="tok-p">);</span>
<span class="tok-n">gtk_list_store_append</span><span class="tok-p">(</span><span class="tok-n">store</span><span class="tok-p">,</span> <span class="tok-o">&</span><span class="tok-n">iter</span><span class="tok-p">);</span>
<span class="tok-n">gtk_list_store_set</span><span class="tok-p">(</span><span class="tok-n">store</span><span class="tok-p">,</span> <span class="tok-o">&</span><span class="tok-n">iter</span><span class="tok-p">,</span> <span class="tok-n">ID</span><span class="tok-p">,</span> <span class="tok-mi">4</span><span class="tok-p">,</span> <span class="tok-n">PROGRAM</span><span class="tok-p">,</span> <span class="tok-s">"Calculator"</span><span class="tok-p">,</span> <span class="tok-n">COLOR1</span><span class="tok-p">,</span> <span class="tok-s">"DarkCyan"</span><span class="tok-p">,</span> <span class="tok-n">COLOR2</span><span class="tok-p">,</span> <span class="tok-s">"cyan"</span><span class="tok-p">,</span> <span class="tok-o">-</span><span class="tok-mi">1</span><span class="tok-p">);</span>
<span class="tok-n">gtk_list_store_append</span><span class="tok-p">(</span><span class="tok-n">store</span><span class="tok-p">,</span> <span class="tok-o">&</span><span class="tok-n">iter</span><span class="tok-p">);</span>
<span class="tok-n">gtk_list_store_set</span><span class="tok-p">(</span><span class="tok-n">store</span><span class="tok-p">,</span> <span class="tok-o">&</span><span class="tok-n">iter</span><span class="tok-p">,</span> <span class="tok-n">ID</span><span class="tok-p">,</span> <span class="tok-mi">5</span><span class="tok-p">,</span> <span class="tok-n">PROGRAM</span><span class="tok-p">,</span> <span class="tok-s">"Devhelp"</span><span class="tok-p">,</span> <span class="tok-n">COLOR1</span><span class="tok-p">,</span> <span class="tok-s">"LightSlateGray"</span><span class="tok-p">,</span> <span class="tok-n">COLOR2</span><span class="tok-p">,</span> <span class="tok-s">"cyan"</span><span class="tok-p">,</span> <span class="tok-o">-</span><span class="tok-mi">1</span><span class="tok-p">);</span>
<span class="tok-n">GtkWidget</span> <span class="tok-o">*</span><span class="tok-n">tree</span><span class="tok-o">=</span><span class="tok-n">gtk_tree_view_new_with_model</span><span class="tok-p">(</span><span class="tok-n">GTK_TREE_MODEL</span><span class="tok-p">(</span><span class="tok-n">store</span><span class="tok-p">));</span>
<span class="tok-n">gtk_widget_set_hexpand</span><span class="tok-p">(</span><span class="tok-n">tree</span><span class="tok-p">,</span> <span class="tok-n">TRUE</span><span class="tok-p">);</span>
<span class="tok-n">gtk_widget_set_vexpand</span><span class="tok-p">(</span><span class="tok-n">tree</span><span class="tok-p">,</span> <span class="tok-n">TRUE</span><span class="tok-p">);</span>
<span class="tok-n">g_object_set</span><span class="tok-p">(</span><span class="tok-n">tree</span><span class="tok-p">,</span> <span class="tok-s">"activate-on-single-click"</span><span class="tok-p">,</span> <span class="tok-n">TRUE</span><span class="tok-p">,</span> <span class="tok-nb">NULL</span><span class="tok-p">);</span>
<span class="tok-n">GtkTreeSelection</span> <span class="tok-o">*</span><span class="tok-n">selection</span><span class="tok-o">=</span><span class="tok-n">gtk_tree_view_get_selection</span><span class="tok-p">(</span><span class="tok-n">GTK_TREE_VIEW</span><span class="tok-p">(</span><span class="tok-n">tree</span><span class="tok-p">));</span>
<span class="tok-n">gtk_tree_selection_set_mode</span><span class="tok-p">(</span><span class="tok-n">selection</span><span class="tok-p">,</span> <span class="tok-n">GTK_SELECTION_SINGLE</span><span class="tok-p">);</span>
<span class="tok-n">GtkCellRenderer</span> <span class="tok-o">*</span><span class="tok-n">renderer1</span><span class="tok-o">=</span><span class="tok-n">gtk_cell_renderer_text_new</span><span class="tok-p">();</span>
<span class="tok-n">g_object_set</span><span class="tok-p">(</span><span class="tok-n">renderer1</span><span class="tok-p">,</span> <span class="tok-s">"editable"</span><span class="tok-p">,</span> <span class="tok-n">FALSE</span><span class="tok-p">,</span> <span class="tok-nb">NULL</span><span class="tok-p">);</span>
<span class="tok-n">GtkCellRenderer</span> <span class="tok-o">*</span><span class="tok-n">renderer2</span><span class="tok-o">=</span><span class="tok-n">gtk_cell_renderer_text_new</span><span class="tok-p">();</span>
<span class="tok-n">g_object_set</span><span class="tok-p">(</span><span class="tok-n">renderer2</span><span class="tok-p">,</span> <span class="tok-s">"editable"</span><span class="tok-p">,</span> <span class="tok-n">TRUE</span><span class="tok-p">,</span> <span class="tok-nb">NULL</span><span class="tok-p">);</span>
<span class="tok-c1">//Bind the COLOR column to the "cell-background" property.</span>
<span class="tok-n">GtkTreeViewColumn</span> <span class="tok-o">*</span><span class="tok-n">column1</span><span class="tok-o">=</span><span class="tok-n">gtk_tree_view_column_new_with_attributes</span><span class="tok-p">(</span><span class="tok-s">"ID"</span><span class="tok-p">,</span> <span class="tok-n">renderer1</span><span class="tok-p">,</span> <span class="tok-s">"text"</span><span class="tok-p">,</span> <span class="tok-n">ID</span><span class="tok-p">,</span> <span class="tok-s">"cell-background"</span><span class="tok-p">,</span> <span class="tok-n">COLOR1</span><span class="tok-p">,</span> <span class="tok-nb">NULL</span><span class="tok-p">);</span>
<span class="tok-n">gtk_tree_view_append_column</span><span class="tok-p">(</span><span class="tok-n">GTK_TREE_VIEW</span><span class="tok-p">(</span><span class="tok-n">tree</span><span class="tok-p">),</span> <span class="tok-n">column1</span><span class="tok-p">);</span>
<span class="tok-n">GtkTreeViewColumn</span> <span class="tok-o">*</span><span class="tok-n">column2</span> <span class="tok-o">=</span> <span class="tok-n">gtk_tree_view_column_new_with_attributes</span><span class="tok-p">(</span><span class="tok-s">"Program"</span><span class="tok-p">,</span> <span class="tok-n">renderer2</span><span class="tok-p">,</span> <span class="tok-s">"text"</span><span class="tok-p">,</span> <span class="tok-n">PROGRAM</span><span class="tok-p">,</span> <span class="tok-s">"cell-background"</span><span class="tok-p">,</span> <span class="tok-n">COLOR2</span><span class="tok-p">,</span> <span class="tok-nb">NULL</span><span class="tok-p">);</span>
<span class="tok-n">gtk_tree_view_append_column</span><span class="tok-p">(</span><span class="tok-n">GTK_TREE_VIEW</span><span class="tok-p">(</span><span class="tok-n">tree</span><span class="tok-p">),</span> <span class="tok-n">column2</span><span class="tok-p">);</span>
<span class="tok-n">GtkWidget</span> <span class="tok-o">*</span><span class="tok-n">grid</span><span class="tok-o">=</span><span class="tok-n">gtk_grid_new</span><span class="tok-p">();</span>
<span class="tok-n">gtk_grid_attach</span><span class="tok-p">(</span><span class="tok-n">GTK_GRID</span><span class="tok-p">(</span><span class="tok-n">grid</span><span class="tok-p">),</span> <span class="tok-n">tree</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">);</span>
<span class="tok-n">gtk_container_add</span><span class="tok-p">(</span><span class="tok-n">GTK_CONTAINER</span><span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">),</span> <span class="tok-n">grid</span><span class="tok-p">);</span>
<span class="tok-n">gchar</span> <span class="tok-o">*</span><span class="tok-n">css_string</span><span class="tok-o">=</span><span class="tok-n">g_strdup</span><span class="tok-p">(</span><span class="tok-s">"treeview{background-color: rgba(0,255,255,1.0); font-size:30pt} treeview:selected{background-color: rgba(255,255,0,1.0); color: rgba(0,0,255,1.0);}"</span><span class="tok-p">);</span>
<span class="tok-n">GError</span> <span class="tok-o">*</span><span class="tok-n">css_error</span><span class="tok-o">=</span><span class="tok-nb">NULL</span><span class="tok-p">;</span>
<span class="tok-n">GtkCssProvider</span> <span class="tok-o">*</span><span class="tok-n">provider</span><span class="tok-o">=</span><span class="tok-n">gtk_css_provider_new</span><span class="tok-p">();</span>
<span class="tok-n">gtk_css_provider_load_from_data</span><span class="tok-p">(</span><span class="tok-n">provider</span><span class="tok-p">,</span> <span class="tok-n">css_string</span><span class="tok-p">,</span> <span class="tok-o">-</span><span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-o">&</span><span class="tok-n">css_error</span><span class="tok-p">);</span>
<span class="tok-n">gtk_style_context_add_provider_for_screen</span><span class="tok-p">(</span><span class="tok-n">gdk_screen_get_default</span><span class="tok-p">(),</span> <span class="tok-n">GTK_STYLE_PROVIDER</span><span class="tok-p">(</span><span class="tok-n">provider</span><span class="tok-p">),</span> <span class="tok-n">GTK_STYLE_PROVIDER_PRIORITY_APPLICATION</span><span class="tok-p">);</span>
<span class="tok-k">if</span><span class="tok-p">(</span><span class="tok-n">css_error</span><span class="tok-o">!=</span><span class="tok-nb">NULL</span><span class="tok-p">)</span>
<span class="tok-p">{</span>
<span class="tok-n">g_print</span><span class="tok-p">(</span><span class="tok-s">"CSS loader error %s</span><span class="tok-se">\n</span><span class="tok-s">"</span><span class="tok-p">,</span> <span class="tok-n">css_error</span><span class="tok-o">-></span><span class="tok-n">message</span><span class="tok-p">);</span>
<span class="tok-n">g_error_free</span><span class="tok-p">(</span><span class="tok-n">css_error</span><span class="tok-p">);</span>
<span class="tok-p">}</span>
<span class="tok-n">g_object_unref</span><span class="tok-p">(</span><span class="tok-n">provider</span><span class="tok-p">);</span>
<span class="tok-n">g_free</span><span class="tok-p">(</span><span class="tok-n">css_string</span><span class="tok-p">);</span>
<span class="tok-n">gtk_widget_show_all</span><span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">);</span>
<span class="tok-n">gtk_main</span><span class="tok-p">();</span>
<span class="tok-k">return</span> <span class="tok-mi">0</span><span class="tok-p">;</span>
<span class="tok-p">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>And this is the Nim version, created with c2nim and some manual tuning:</p>
</div>
<div id="css_colored_listview.nim" class="listingblock">
<div class="title">css_colored_listview.nim</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="nim"><span></span><span class="tok-c"># nim c css_colored_listview.nim</span>
<span class="tok-kn">import</span> <span class="tok-n">gintro</span><span class="tok-o">/[</span><span class="tok-n">gtk</span><span class="tok-p">,</span> <span class="tok-n">glib</span><span class="tok-p">,</span> <span class="tok-n">gobject</span><span class="tok-o">]</span>
<span class="tok-kn">import</span> <span class="tok-n">gintro</span><span class="tok-o">/</span><span class="tok-n">gdk</span> <span class="tok-k">except</span> <span class="tok-n">Window</span> <span class="tok-c"># there is a problem with gdk.Window -- we have to investigate!</span>
<span class="tok-k">const</span> <span class="tok-c"># maybe we should use Nim's enum here?</span>
<span class="tok-n">Id</span> <span class="tok-o">=</span> <span class="tok-mi">0</span>
<span class="tok-n">Program</span> <span class="tok-o">=</span> <span class="tok-mi">1</span>
<span class="tok-n">Color1</span> <span class="tok-o">=</span> <span class="tok-mi">2</span>
<span class="tok-n">Color2</span> <span class="tok-o">=</span> <span class="tok-mi">3</span>
<span class="tok-n">Columns</span> <span class="tok-o">=</span> <span class="tok-mi">4</span>
<span class="tok-k">proc </span><span class="tok-nf">bye</span><span class="tok-p">(</span><span class="tok-n">w</span><span class="tok-p">:</span> <span class="tok-n">Window</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">mainQuit</span><span class="tok-p">()</span>
<span class="tok-n">echo</span> <span class="tok-s">"Bye..."</span>
<span class="tok-k">proc </span><span class="tok-nf">toStringVal</span><span class="tok-p">(</span><span class="tok-n">s</span><span class="tok-p">:</span> <span class="tok-kt">string</span><span class="tok-p">):</span> <span class="tok-n">Value</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">gtype</span> <span class="tok-o">=</span> <span class="tok-n">typeFromName</span><span class="tok-p">(</span><span class="tok-s">"gchararray"</span><span class="tok-p">)</span>
<span class="tok-k">discard</span> <span class="tok-n">init</span><span class="tok-p">(</span><span class="tok-n">result</span><span class="tok-p">,</span> <span class="tok-n">gtype</span><span class="tok-p">)</span>
<span class="tok-n">setString</span><span class="tok-p">(</span><span class="tok-n">result</span><span class="tok-p">,</span> <span class="tok-n">s</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">toUIntVal</span><span class="tok-p">(</span><span class="tok-n">i</span><span class="tok-p">:</span> <span class="tok-kt">int</span><span class="tok-p">):</span> <span class="tok-n">Value</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">gtype</span> <span class="tok-o">=</span> <span class="tok-n">typeFromName</span><span class="tok-p">(</span><span class="tok-s">"guint"</span><span class="tok-p">)</span>
<span class="tok-k">discard</span> <span class="tok-n">init</span><span class="tok-p">(</span><span class="tok-n">result</span><span class="tok-p">,</span> <span class="tok-n">gtype</span><span class="tok-p">)</span>
<span class="tok-n">setUint</span><span class="tok-p">(</span><span class="tok-n">result</span><span class="tok-p">,</span> <span class="tok-n">i</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">toBoolVal</span><span class="tok-p">(</span><span class="tok-n">b</span><span class="tok-p">:</span> <span class="tok-kt">bool</span><span class="tok-p">):</span> <span class="tok-n">Value</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">gtype</span> <span class="tok-o">=</span> <span class="tok-n">typeFromName</span><span class="tok-p">(</span><span class="tok-s">"gboolean"</span><span class="tok-p">)</span>
<span class="tok-k">discard</span> <span class="tok-n">init</span><span class="tok-p">(</span><span class="tok-n">result</span><span class="tok-p">,</span> <span class="tok-n">gtype</span><span class="tok-p">)</span>
<span class="tok-n">setBoolean</span><span class="tok-p">(</span><span class="tok-n">result</span><span class="tok-p">,</span> <span class="tok-n">b</span><span class="tok-p">)</span>
<span class="tok-c"># we need the following two procs for now -- later we will not use that ugly cast...</span>
<span class="tok-k">proc </span><span class="tok-nf">typeTest</span><span class="tok-p">(</span><span class="tok-n">o</span><span class="tok-p">:</span> <span class="tok-n">gobject</span><span class="tok-p">.</span><span class="tok-k">Object</span><span class="tok-p">;</span> <span class="tok-n">s</span><span class="tok-p">:</span> <span class="tok-kt">string</span><span class="tok-p">):</span> <span class="tok-kt">bool</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">gt</span> <span class="tok-o">=</span> <span class="tok-n">g_type_from_name</span><span class="tok-p">(</span><span class="tok-n">s</span><span class="tok-p">)</span>
<span class="tok-k">return</span> <span class="tok-n">g_type_check_instance_is_a</span><span class="tok-p">(</span><span class="tok-k">cast</span><span class="tok-o">[</span><span class="tok-k">ptr</span> <span class="tok-n">TypeInstance00</span><span class="tok-o">]</span><span class="tok-p">(</span><span class="tok-n">o</span><span class="tok-p">.</span><span class="tok-n">impl</span><span class="tok-p">),</span> <span class="tok-n">gt</span><span class="tok-p">).</span><span class="tok-n">toBool</span>
<span class="tok-k">proc </span><span class="tok-nf">listStore</span><span class="tok-p">(</span><span class="tok-n">o</span><span class="tok-p">:</span> <span class="tok-n">gobject</span><span class="tok-p">.</span><span class="tok-k">Object</span><span class="tok-p">):</span> <span class="tok-n">gtk</span><span class="tok-p">.</span><span class="tok-n">ListStore</span> <span class="tok-o">=</span>
<span class="tok-n">assert</span><span class="tok-p">(</span><span class="tok-n">typeTest</span><span class="tok-p">(</span><span class="tok-n">o</span><span class="tok-p">,</span> <span class="tok-s">"GtkListStore"</span><span class="tok-p">))</span>
<span class="tok-k">cast</span><span class="tok-o">[</span><span class="tok-n">gtk</span><span class="tok-p">.</span><span class="tok-n">ListStore</span><span class="tok-o">]</span><span class="tok-p">(</span><span class="tok-n">o</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">updateRow</span><span class="tok-p">(</span><span class="tok-n">renderer</span><span class="tok-p">:</span> <span class="tok-n">CellRendererText</span><span class="tok-p">;</span> <span class="tok-n">path</span><span class="tok-p">:</span> <span class="tok-n">cstring</span><span class="tok-p">;</span> <span class="tok-n">newText</span><span class="tok-p">:</span> <span class="tok-n">cstring</span><span class="tok-p">;</span> <span class="tok-n">tree</span><span class="tok-p">:</span> <span class="tok-n">TreeView</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-kd">var</span> <span class="tok-n">iter</span><span class="tok-p">:</span> <span class="tok-n">TreeIter</span>
<span class="tok-kd">var</span> <span class="tok-n">value</span><span class="tok-p">:</span> <span class="tok-n">Value</span>
<span class="tok-k">let</span> <span class="tok-n">gtype</span> <span class="tok-o">=</span> <span class="tok-n">typeFromName</span><span class="tok-p">(</span><span class="tok-s">"gchararray"</span><span class="tok-p">)</span>
<span class="tok-k">discard</span> <span class="tok-n">init</span><span class="tok-p">(</span><span class="tok-n">value</span><span class="tok-p">,</span> <span class="tok-n">gtype</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">store</span> <span class="tok-o">=</span> <span class="tok-n">listStore</span><span class="tok-p">(</span><span class="tok-n">tree</span><span class="tok-p">.</span><span class="tok-n">getModel</span><span class="tok-p">())</span>
<span class="tok-n">value</span><span class="tok-p">.</span><span class="tok-n">setString</span><span class="tok-p">(</span><span class="tok-n">newText</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">treePath</span> <span class="tok-o">=</span> <span class="tok-n">newTreePathFromString</span><span class="tok-p">(</span><span class="tok-n">path</span><span class="tok-p">)</span>
<span class="tok-k">discard</span> <span class="tok-n">store</span><span class="tok-p">.</span><span class="tok-n">getIter</span><span class="tok-p">(</span><span class="tok-n">iter</span><span class="tok-p">,</span> <span class="tok-n">treePath</span><span class="tok-p">)</span>
<span class="tok-n">store</span><span class="tok-p">.</span><span class="tok-n">setValue</span><span class="tok-p">(</span><span class="tok-n">iter</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-n">value</span><span class="tok-p">)</span>
<span class="tok-c"># we use the old gtk style with init() as is used in the C original -- maybe better use modern app sytle</span>
<span class="tok-k">proc </span><span class="tok-nf">main</span><span class="tok-p">()</span> <span class="tok-o">=</span>
<span class="tok-n">gtk</span><span class="tok-p">.</span><span class="tok-n">init</span><span class="tok-p">()</span>
<span class="tok-k">let</span> <span class="tok-n">window</span> <span class="tok-o">=</span> <span class="tok-n">newWindow</span><span class="tok-p">()</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">title</span> <span class="tok-o">=</span> <span class="tok-s">"Select Cell"</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">position</span> <span class="tok-o">=</span> <span class="tok-n">WindowPosition</span><span class="tok-p">.</span><span class="tok-n">center</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">defaultSize</span> <span class="tok-o">=</span> <span class="tok-p">(</span><span class="tok-mi">500</span><span class="tok-p">,</span> <span class="tok-mi">500</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">borderWidth</span> <span class="tok-o">=</span> <span class="tok-mi">20</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">,</span> <span class="tok-s">"destroy"</span><span class="tok-p">,</span> <span class="tok-n">bye</span><span class="tok-p">)</span>
<span class="tok-kd">var</span> <span class="tok-n">iter</span><span class="tok-p">:</span> <span class="tok-n">TreeIter</span>
<span class="tok-kd">var</span> <span class="tok-n">h</span> <span class="tok-o">=</span> <span class="tok-o">[</span><span class="tok-n">typeFromName</span><span class="tok-p">(</span><span class="tok-s">"guint"</span><span class="tok-p">),</span> <span class="tok-n">typeFromName</span><span class="tok-p">(</span><span class="tok-s">"gchararray"</span><span class="tok-p">),</span> <span class="tok-n">typeFromName</span><span class="tok-p">(</span><span class="tok-s">"gchararray"</span><span class="tok-p">),</span>
<span class="tok-n">typeFromName</span><span class="tok-p">(</span><span class="tok-s">"gchararray"</span><span class="tok-p">)</span><span class="tok-o">]</span>
<span class="tok-kd">var</span> <span class="tok-n">store</span> <span class="tok-o">=</span> <span class="tok-n">newListStore</span><span class="tok-p">(</span><span class="tok-n">Columns</span><span class="tok-p">,</span> <span class="tok-k">cast</span><span class="tok-o">[</span><span class="tok-n">pointer</span><span class="tok-o">]</span><span class="tok-p">(</span> <span class="tok-n">unsafeaddr</span> <span class="tok-n">h</span><span class="tok-p">))</span> <span class="tok-c"># cast is ugly, we should fix it in bindings.</span>
<span class="tok-k">let</span> <span class="tok-n">progNames</span> <span class="tok-o">=</span> <span class="tok-o">[</span><span class="tok-s">"Gedit"</span><span class="tok-p">,</span> <span class="tok-s">"Gimp"</span><span class="tok-p">,</span> <span class="tok-s">"Inkscape"</span><span class="tok-p">,</span> <span class="tok-s">"Firefox"</span><span class="tok-p">,</span> <span class="tok-s">"Calculator"</span><span class="tok-p">,</span> <span class="tok-s">"Devhelp"</span><span class="tok-o">]</span>
<span class="tok-k">for</span> <span class="tok-n">i</span><span class="tok-p">,</span> <span class="tok-n">n</span> <span class="tok-ow">in</span> <span class="tok-n">progNames</span><span class="tok-p">:</span>
<span class="tok-n">store</span><span class="tok-p">.</span><span class="tok-n">append</span><span class="tok-p">(</span><span class="tok-n">iter</span><span class="tok-p">)</span> <span class="tok-c"># currently we have to use setValue() as there is no varargs proc as in C original</span>
<span class="tok-n">store</span><span class="tok-p">.</span><span class="tok-n">setValue</span><span class="tok-p">(</span><span class="tok-n">iter</span><span class="tok-p">,</span> <span class="tok-n">Id</span><span class="tok-p">,</span> <span class="tok-n">toUIntVal</span><span class="tok-p">(</span><span class="tok-n">i</span><span class="tok-p">))</span>
<span class="tok-n">store</span><span class="tok-p">.</span><span class="tok-n">setValue</span><span class="tok-p">(</span><span class="tok-n">iter</span><span class="tok-p">,</span> <span class="tok-n">Program</span><span class="tok-p">,</span> <span class="tok-n">toStringVal</span><span class="tok-p">(</span><span class="tok-n">n</span><span class="tok-p">))</span>
<span class="tok-n">store</span><span class="tok-p">.</span><span class="tok-n">setValue</span><span class="tok-p">(</span><span class="tok-n">iter</span><span class="tok-p">,</span> <span class="tok-n">Color1</span><span class="tok-p">,</span> <span class="tok-n">toStringVal</span><span class="tok-p">(</span><span class="tok-k">if</span> <span class="tok-p">(</span><span class="tok-n">i</span> <span class="tok-ow">and</span> <span class="tok-mi">1</span><span class="tok-p">)</span> <span class="tok-o">!=</span> <span class="tok-mi">0</span><span class="tok-p">:</span> <span class="tok-s">"LightSlateGray"</span> <span class="tok-k">else</span><span class="tok-p">:</span> <span class="tok-s">"DarkCyan"</span><span class="tok-p">))</span>
<span class="tok-n">store</span><span class="tok-p">.</span><span class="tok-n">setValue</span><span class="tok-p">(</span><span class="tok-n">iter</span><span class="tok-p">,</span> <span class="tok-n">Color2</span><span class="tok-p">,</span> <span class="tok-n">toStringVal</span><span class="tok-p">(</span><span class="tok-s">"cyan"</span><span class="tok-p">))</span>
<span class="tok-kd">var</span> <span class="tok-n">tree</span> <span class="tok-o">=</span> <span class="tok-n">newTreeViewWithModel</span><span class="tok-p">(</span><span class="tok-n">store</span><span class="tok-p">)</span>
<span class="tok-n">tree</span><span class="tok-p">.</span><span class="tok-n">setHexpand</span>
<span class="tok-n">tree</span><span class="tok-p">.</span><span class="tok-n">setVexpand</span>
<span class="tok-n">setProperty</span><span class="tok-p">(</span><span class="tok-n">tree</span><span class="tok-p">,</span> <span class="tok-s">"activate-on-single-click"</span><span class="tok-p">,</span> <span class="tok-n">toBoolVal</span><span class="tok-p">(</span><span class="tok-kp">true</span><span class="tok-p">))</span>
<span class="tok-kd">var</span> <span class="tok-n">selection</span> <span class="tok-o">=</span> <span class="tok-n">tree</span><span class="tok-p">.</span><span class="tok-n">getSelection</span><span class="tok-p">()</span>
<span class="tok-n">selection</span><span class="tok-p">.</span><span class="tok-n">setMode</span><span class="tok-p">(</span><span class="tok-n">SelectionMode</span><span class="tok-p">.</span><span class="tok-n">single</span><span class="tok-p">)</span>
<span class="tok-kd">var</span> <span class="tok-n">renderer1</span> <span class="tok-o">=</span> <span class="tok-n">newCellRendererText</span><span class="tok-p">()</span>
<span class="tok-n">setProperty</span><span class="tok-p">(</span><span class="tok-n">renderer1</span><span class="tok-p">,</span> <span class="tok-s">"editable"</span><span class="tok-p">,</span> <span class="tok-n">toBoolVal</span><span class="tok-p">(</span><span class="tok-kp">false</span><span class="tok-p">))</span>
<span class="tok-kd">var</span> <span class="tok-n">renderer2</span> <span class="tok-o">=</span> <span class="tok-n">newCellRendererText</span><span class="tok-p">()</span>
<span class="tok-n">setProperty</span><span class="tok-p">(</span><span class="tok-n">renderer2</span><span class="tok-p">,</span> <span class="tok-s">"editable"</span><span class="tok-p">,</span> <span class="tok-n">toBoolVal</span><span class="tok-p">(</span><span class="tok-kp">true</span><span class="tok-p">))</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">renderer2</span><span class="tok-p">,</span> <span class="tok-s">"edited"</span><span class="tok-p">,</span> <span class="tok-n">updateRow</span><span class="tok-p">,</span> <span class="tok-n">tree</span><span class="tok-p">)</span>
<span class="tok-sd">## Bind the Color column to the "cell-background" property.</span>
<span class="tok-kd">var</span> <span class="tok-n">column1</span> <span class="tok-o">=</span> <span class="tok-n">newTreeViewColumn</span><span class="tok-p">()</span>
<span class="tok-n">column1</span><span class="tok-p">.</span><span class="tok-n">setTitle</span><span class="tok-p">(</span><span class="tok-s">"ID"</span><span class="tok-p">)</span>
<span class="tok-n">column1</span><span class="tok-p">.</span><span class="tok-n">packStart</span><span class="tok-p">(</span><span class="tok-n">renderer1</span><span class="tok-p">,</span> <span class="tok-kp">true</span><span class="tok-p">)</span>
<span class="tok-n">column1</span><span class="tok-p">.</span><span class="tok-n">addAttribute</span><span class="tok-p">(</span><span class="tok-n">renderer1</span><span class="tok-p">,</span> <span class="tok-s">"text"</span><span class="tok-p">,</span> <span class="tok-n">Id</span><span class="tok-p">)</span>
<span class="tok-n">column1</span><span class="tok-p">.</span><span class="tok-n">addAttribute</span><span class="tok-p">(</span><span class="tok-n">renderer1</span><span class="tok-p">,</span> <span class="tok-s">"cell-background"</span><span class="tok-p">,</span> <span class="tok-n">Color1</span><span class="tok-p">)</span>
<span class="tok-k">discard</span> <span class="tok-n">tree</span><span class="tok-p">.</span><span class="tok-n">appendColumn</span><span class="tok-p">(</span><span class="tok-n">column1</span><span class="tok-p">)</span>
<span class="tok-kd">var</span> <span class="tok-n">column2</span> <span class="tok-o">=</span> <span class="tok-n">newTreeViewColumn</span><span class="tok-p">()</span>
<span class="tok-n">column1</span><span class="tok-p">.</span><span class="tok-n">setTitle</span><span class="tok-p">(</span><span class="tok-s">"Program"</span><span class="tok-p">)</span>
<span class="tok-n">column1</span><span class="tok-p">.</span><span class="tok-n">packStart</span><span class="tok-p">(</span><span class="tok-n">renderer2</span><span class="tok-p">,</span> <span class="tok-kp">true</span><span class="tok-p">)</span>
<span class="tok-n">column1</span><span class="tok-p">.</span><span class="tok-n">addAttribute</span><span class="tok-p">(</span><span class="tok-n">renderer2</span><span class="tok-p">,</span> <span class="tok-s">"text"</span><span class="tok-p">,</span> <span class="tok-n">Program</span><span class="tok-p">)</span>
<span class="tok-n">column1</span><span class="tok-p">.</span><span class="tok-n">addAttribute</span><span class="tok-p">(</span><span class="tok-n">renderer2</span><span class="tok-p">,</span> <span class="tok-s">"cell-background"</span><span class="tok-p">,</span> <span class="tok-n">Color2</span><span class="tok-p">)</span>
<span class="tok-k">discard</span> <span class="tok-n">tree</span><span class="tok-p">.</span><span class="tok-n">appendColumn</span><span class="tok-p">(</span><span class="tok-n">column2</span><span class="tok-p">)</span>
<span class="tok-kd">var</span> <span class="tok-n">grid</span> <span class="tok-o">=</span> <span class="tok-n">newGrid</span><span class="tok-p">()</span> <span class="tok-c"># only one occupied cell makes no sense -- but so we can add more widgets later</span>
<span class="tok-n">grid</span><span class="tok-p">.</span><span class="tok-n">attach</span><span class="tok-p">(</span><span class="tok-n">tree</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">add</span><span class="tok-p">(</span><span class="tok-n">grid</span><span class="tok-p">)</span>
<span class="tok-k">const</span> <span class="tok-n">cssString</span> <span class="tok-o">=</span> <span class="tok-c"># note: big font selected intentionally</span>
<span class="tok-s">"""treeview{background-color: rgba(0,255,255,1.0); font-size:30pt} treeview:selected{background-color:</span>
<span class="tok-s"> rgba(255,255,0,1.0); color: rgba(0,0,255,1.0);}"""</span>
<span class="tok-kd">var</span> <span class="tok-n">provider</span> <span class="tok-o">=</span> <span class="tok-n">newCssProvider</span><span class="tok-p">()</span>
<span class="tok-k">discard</span> <span class="tok-n">provider</span><span class="tok-p">.</span><span class="tok-n">loadFromData</span><span class="tok-p">(</span><span class="tok-n">cssString</span><span class="tok-p">)</span>
<span class="tok-n">addProviderForScreen</span><span class="tok-p">(</span><span class="tok-n">getDefaultScreen</span><span class="tok-p">(),</span> <span class="tok-n">provider</span><span class="tok-p">,</span> <span class="tok-n">STYLE_PROVIDER_PRIORITY_APPLICATION</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">showAll</span>
<span class="tok-n">gtk</span><span class="tok-p">.</span><span class="tok-n">main</span><span class="tok-p">()</span>
<span class="tok-n">main</span><span class="tok-p">()</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>When you compile with <code>nim c -d:release -d:danger --passC:-flto css_colored_listview.nim</code>
you will get an executable size of 80k, which is big compared with the 20k of the C version, but
not too bad. You may note that I have added the updateRow() proc, which is necessary to
make editing the program name entries permanent. That proc needs cstring parametes, which
may be surprising, as we generally use Nim strings. Not a big problem, maybe intended, we may have to
check the connect() macro in gimpl.nim.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_a_more_advanced_example_for_cairo_drawing_with_zooming_panning_scrolling">A more advanced example for cairo drawing with zooming, panning, scrolling</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The following code is a plain Nim version of a drawing demo which I wrote some years ago in Ruby (<a href="http://ssalewski.de/PetEd-Demo.html.en" class="bare">http://ssalewski.de/PetEd-Demo.html.en</a>).
Cairo surface is currently manually freed, because GC may have a too large delay.</p>
</div>
<div class="paragraph">
<p>You can resize the window and zoom in with the mouse wheel. When zoomed in scroll bars appear. You
can hold the middle mouse button pressed while moving the mouse for panning, and you can press left mouse button
and move the mouse to first draw a selection rectangle and zoom into it when releasing the mouse button.</p>
</div>
<div class="paragraph">
<p>In the examples directory there is also a simplified version called <code>simpledrawingarea.nim</code> which does all
the drawings in the draw callback, without using a buffering surface. This is generally preferable for
plain applications.</p>
</div>
<div id="drawingarea.nim" class="listingblock">
<div class="title">drawingarea.nim</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="nim"><span></span><span class="tok-c"># Plain demo for zooming, panning, scrolling with GTK DrawingArea</span>
<span class="tok-c"># (c) S. Salewski, 21-DEC-2010 (initial Ruby version)</span>
<span class="tok-c"># Nim version April 2019</span>
<span class="tok-c"># License MIT</span>
<span class="tok-c"># This version of the demo program uses a separate proc paint()</span>
<span class="tok-c"># which allocates a custom surface for buffered drawing.</span>
<span class="tok-c"># That may be not really necessary, for simple drawings doing all</span>
<span class="tok-c"># the drawing in the "draw" call back is easier and faster. But for</span>
<span class="tok-c"># more complicated drawing operations, for example when using a</span>
<span class="tok-c"># background grid, which is a bit larger than the window size and</span>
<span class="tok-c"># is reused when scrolling, a custom surface may be useful.</span>
<span class="tok-c"># And finally that custom surface and custom cairo context is an</span>
<span class="tok-c"># important test for the language bindings.</span>
<span class="tok-c"># https://discourse.gnome.org/t/problem-with-gtkscrollbar-gtk-window-resize-and-gtk-adjustment-set-value/1081</span>
<span class="tok-kn">import</span> <span class="tok-n">gintro</span><span class="tok-o">/[</span><span class="tok-n">gtk</span><span class="tok-p">,</span> <span class="tok-n">gdk</span><span class="tok-p">,</span> <span class="tok-n">glib</span><span class="tok-p">,</span> <span class="tok-n">gobject</span><span class="tok-p">,</span> <span class="tok-n">gio</span><span class="tok-p">,</span> <span class="tok-n">cairo</span><span class="tok-o">]</span>
<span class="tok-k">const</span>
<span class="tok-n">ZoomFactorMouseWheel</span> <span class="tok-o">=</span> <span class="tok-mf">1.1</span>
<span class="tok-n">ZoomFactorSelectMax</span> <span class="tok-o">=</span> <span class="tok-mi">10</span> <span class="tok-c"># ignore zooming in tiny selection</span>
<span class="tok-n">ZoomNearMousepointer</span> <span class="tok-o">=</span> <span class="tok-kp">true</span> <span class="tok-c"># mouse wheel zooming -- to mouse-pointer or center</span>
<span class="tok-n">SelectRectCol</span> <span class="tok-o">=</span> <span class="tok-o">[</span><span class="tok-mf">0.0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mf">0.5</span><span class="tok-o">]</span> <span class="tok-c"># blue with transparency</span>
<span class="tok-k">discard</span> <span class="tok-s">"""</span>
<span class="tok-s">Zooming, scrolling, panning...</span>
<span class="tok-s">|-------------------------|</span>
<span class="tok-s">|<-------- A ------------>|</span>
<span class="tok-s">| |</span>
<span class="tok-s">| |---------------| |</span>
<span class="tok-s">| | <---- a ----->| |</span>
<span class="tok-s">| | visible | |</span>
<span class="tok-s">| |---------------| |</span>
<span class="tok-s">| |</span>
<span class="tok-s">| |</span>
<span class="tok-s">|-------------------------|</span>
<span class="tok-s">a is the visible, zoomed in area == darea.allocatedWidth</span>
<span class="tok-s">A is the total data range</span>
<span class="tok-s">A/a == userZoom >= 1</span>
<span class="tok-s">For horizontal adjustment we use</span>
<span class="tok-s">hadjustment.setUpper(darea.allocatedWidth * userZoom) == A</span>
<span class="tok-s">hadjustment.setPageSize(darea.allocatedWidth) == a</span>
<span class="tok-s">So hadjustment.value == left side of visible area</span>
<span class="tok-s">Initially, we set userZoom = 1, scale our data to fit into darea.allocatedWidth</span>
<span class="tok-s">and translate the origin of our data to (0, 0)</span>
<span class="tok-s">Zooming: Mouse wheel or selecting a rectangle with left mouse button pressed</span>
<span class="tok-s">Scrolling: Scrollbars</span>
<span class="tok-s">Panning: Moving mouse while middle mouse button pressed</span>
<span class="tok-s">"""</span>
<span class="tok-c"># drawing area and scroll bars in 2x2 grid (PDA == Plain Drawing Area)</span>
<span class="tok-k">type</span>
<span class="tok-n">PosAdj</span> <span class="tok-o">=</span> <span class="tok-k">ref</span> <span class="tok-k">object</span> <span class="tok-k">of</span> <span class="tok-n">Adjustment</span>
<span class="tok-n">handlerID</span><span class="tok-p">:</span> <span class="tok-n">uint64</span>
<span class="tok-k">proc </span><span class="tok-nf">newPosAdj</span><span class="tok-p">:</span> <span class="tok-n">PosAdj</span> <span class="tok-o">=</span>
<span class="tok-n">initAdjustment</span><span class="tok-p">(</span><span class="tok-n">result</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">10</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">)</span>
<span class="tok-k">type</span>
<span class="tok-n">PDA_Data</span><span class="tok-o">*</span> <span class="tok-o">=</span> <span class="tok-k">object</span>
<span class="tok-n">draw</span><span class="tok-o">*</span><span class="tok-p">:</span> <span class="tok-k">proc</span> <span class="tok-p">(</span><span class="tok-n">cr</span><span class="tok-p">:</span> <span class="tok-n">Context</span><span class="tok-p">)</span>
<span class="tok-n">extents</span><span class="tok-o">*</span><span class="tok-p">:</span> <span class="tok-k">proc</span> <span class="tok-p">():</span> <span class="tok-k">tuple</span><span class="tok-o">[</span><span class="tok-n">x</span><span class="tok-p">,</span> <span class="tok-n">y</span><span class="tok-p">,</span> <span class="tok-n">w</span><span class="tok-p">,</span> <span class="tok-n">h</span><span class="tok-p">:</span> <span class="tok-kt">float</span><span class="tok-o">]</span>
<span class="tok-n">windowSize</span><span class="tok-o">*</span><span class="tok-p">:</span> <span class="tok-k">tuple</span><span class="tok-o">[</span><span class="tok-n">w</span><span class="tok-p">,</span> <span class="tok-n">h</span><span class="tok-p">:</span> <span class="tok-kt">int</span><span class="tok-o">]</span>
<span class="tok-k">type</span>
<span class="tok-n">PDA</span> <span class="tok-o">=</span> <span class="tok-k">ref</span> <span class="tok-k">object</span> <span class="tok-k">of</span> <span class="tok-n">Grid</span>
<span class="tok-n">zoomNearMousepointer</span><span class="tok-p">:</span> <span class="tok-kt">bool</span>
<span class="tok-n">selecting</span><span class="tok-p">:</span> <span class="tok-kt">bool</span>
<span class="tok-n">userZoom</span><span class="tok-p">:</span> <span class="tok-kt">float</span>
<span class="tok-n">surf</span><span class="tok-p">:</span> <span class="tok-n">Surface</span>
<span class="tok-n">pattern</span><span class="tok-p">:</span> <span class="tok-n">Pattern</span>
<span class="tok-n">cr</span><span class="tok-p">:</span> <span class="tok-n">cairo</span><span class="tok-p">.</span><span class="tok-n">Context</span>
<span class="tok-n">darea</span><span class="tok-p">:</span> <span class="tok-n">DrawingArea</span>
<span class="tok-n">hadjustment</span><span class="tok-p">:</span> <span class="tok-n">PosAdj</span>
<span class="tok-n">vadjustment</span><span class="tok-p">:</span> <span class="tok-n">PosAdj</span>
<span class="tok-n">hscrollbar</span><span class="tok-p">:</span> <span class="tok-n">Scrollbar</span>
<span class="tok-n">vscrollbar</span><span class="tok-p">:</span> <span class="tok-n">Scrollbar</span>
<span class="tok-n">fullScale</span><span class="tok-p">:</span> <span class="tok-kt">float</span>
<span class="tok-n">dataX</span><span class="tok-p">:</span> <span class="tok-kt">float</span>
<span class="tok-n">dataY</span><span class="tok-p">:</span> <span class="tok-kt">float</span>
<span class="tok-n">dataWidth</span><span class="tok-p">:</span> <span class="tok-kt">float</span>
<span class="tok-n">dataHeight</span><span class="tok-p">:</span> <span class="tok-kt">float</span>
<span class="tok-n">lastButtonDownPosX</span><span class="tok-p">:</span> <span class="tok-kt">float</span>
<span class="tok-n">lastButtonDownPosY</span><span class="tok-p">:</span> <span class="tok-kt">float</span>
<span class="tok-n">lastMousePosX</span><span class="tok-p">:</span> <span class="tok-kt">float</span>
<span class="tok-n">lastMousePosY</span><span class="tok-p">:</span> <span class="tok-kt">float</span>
<span class="tok-n">zoomRectX1</span><span class="tok-p">:</span> <span class="tok-kt">float</span>
<span class="tok-n">zoomRectY1</span><span class="tok-p">:</span> <span class="tok-kt">float</span>
<span class="tok-n">oldSizeX</span><span class="tok-p">:</span> <span class="tok-kt">int</span>
<span class="tok-n">oldSizeY</span><span class="tok-p">:</span> <span class="tok-kt">int</span>
<span class="tok-n">drawWorld</span><span class="tok-p">:</span> <span class="tok-k">proc</span> <span class="tok-p">(</span><span class="tok-n">cr</span><span class="tok-p">:</span> <span class="tok-n">Context</span><span class="tok-p">)</span>
<span class="tok-n">extents</span><span class="tok-p">:</span> <span class="tok-k">proc</span> <span class="tok-p">():</span> <span class="tok-k">tuple</span><span class="tok-o">[</span><span class="tok-n">x</span><span class="tok-p">,</span> <span class="tok-n">y</span><span class="tok-p">,</span> <span class="tok-n">w</span><span class="tok-p">,</span> <span class="tok-n">h</span><span class="tok-p">:</span> <span class="tok-kt">float</span><span class="tok-o">]</span>
<span class="tok-k">proc </span><span class="tok-nf">drawingAreaDrawCb</span><span class="tok-p">(</span><span class="tok-n">darea</span><span class="tok-p">:</span> <span class="tok-n">DrawingArea</span><span class="tok-p">;</span> <span class="tok-n">cr</span><span class="tok-p">:</span> <span class="tok-n">Context</span><span class="tok-p">;</span> <span class="tok-n">this</span><span class="tok-p">:</span> <span class="tok-n">PDA</span><span class="tok-p">):</span> <span class="tok-kt">bool</span> <span class="tok-o">=</span>
<span class="tok-k">if</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">pattern</span><span class="tok-p">.</span><span class="tok-n">isNil</span><span class="tok-p">:</span> <span class="tok-k">return</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">setSource</span><span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">pattern</span><span class="tok-p">)</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">paint</span>
<span class="tok-k">if</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">selecting</span><span class="tok-p">:</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">rectangle</span><span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">lastButtonDownPosX</span><span class="tok-p">,</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">lastButtonDownPosY</span><span class="tok-p">,</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">zoomRectX1</span> <span class="tok-o">-</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">lastButtonDownPosX</span><span class="tok-p">,</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">zoomRectY1</span> <span class="tok-o">-</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">lastButtonDownPosY</span><span class="tok-p">)</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">setSource</span><span class="tok-p">(</span><span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mf">0.5</span><span class="tok-p">)</span> <span class="tok-c"># SELECT_RECT_COL) # 0, 0, 1, 0.5</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">fillPreserve</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">setSource</span><span class="tok-p">(</span><span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">)</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">setLineWidth</span><span class="tok-p">(</span><span class="tok-mi">2</span><span class="tok-p">)</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">stroke</span>
<span class="tok-k">return</span> <span class="tok-n">gdk</span><span class="tok-p">.</span><span class="tok-n">EVENT_STOP</span> <span class="tok-c"># EVENT_PROPAGATE</span>
<span class="tok-c">#return true # TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.</span>
<span class="tok-c"># clamp to correct values, 0 <= value <= (adj.upper - adj.pageSize), block calling onAdjustmentEvent()</span>
<span class="tok-k">proc </span><span class="tok-nf">updateVal</span><span class="tok-p">(</span><span class="tok-n">adj</span><span class="tok-p">:</span> <span class="tok-n">PosAdj</span><span class="tok-p">;</span> <span class="tok-n">d</span><span class="tok-p">:</span> <span class="tok-kt">float</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">adj</span><span class="tok-p">.</span><span class="tok-n">signalHandlerBlock</span><span class="tok-p">(</span><span class="tok-n">adj</span><span class="tok-p">.</span><span class="tok-n">handlerID</span><span class="tok-p">)</span>
<span class="tok-n">adj</span><span class="tok-p">.</span><span class="tok-n">setValue</span><span class="tok-p">(</span><span class="tok-n">max</span><span class="tok-p">(</span><span class="tok-mf">0.0</span><span class="tok-p">,</span> <span class="tok-n">min</span><span class="tok-p">(</span><span class="tok-n">adj</span><span class="tok-p">.</span><span class="tok-n">value</span> <span class="tok-o">+</span> <span class="tok-n">d</span><span class="tok-p">,</span> <span class="tok-n">adj</span><span class="tok-p">.</span><span class="tok-n">upper</span> <span class="tok-o">-</span> <span class="tok-n">adj</span><span class="tok-p">.</span><span class="tok-n">pageSize</span><span class="tok-p">)))</span>
<span class="tok-n">adj</span><span class="tok-p">.</span><span class="tok-n">signalHandlerUnblock</span><span class="tok-p">(</span><span class="tok-n">adj</span><span class="tok-p">.</span><span class="tok-n">handlerID</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">updateAdjustments</span><span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">:</span> <span class="tok-n">PDA</span><span class="tok-p">;</span> <span class="tok-n">dx</span><span class="tok-p">,</span> <span class="tok-n">dy</span><span class="tok-p">:</span> <span class="tok-kt">float</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">hadjustment</span><span class="tok-p">.</span><span class="tok-n">setUpper</span><span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">darea</span><span class="tok-p">.</span><span class="tok-n">allocatedWidth</span><span class="tok-p">.</span><span class="tok-kt">float</span> <span class="tok-o">*</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">userZoom</span><span class="tok-p">)</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">vadjustment</span><span class="tok-p">.</span><span class="tok-n">setUpper</span><span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">darea</span><span class="tok-p">.</span><span class="tok-n">allocatedHeight</span><span class="tok-p">.</span><span class="tok-kt">float</span> <span class="tok-o">*</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">userZoom</span><span class="tok-p">)</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">hadjustment</span><span class="tok-p">.</span><span class="tok-n">setPageSize</span><span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">darea</span><span class="tok-p">.</span><span class="tok-n">allocatedWidth</span><span class="tok-p">.</span><span class="tok-kt">float</span><span class="tok-p">)</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">vadjustment</span><span class="tok-p">.</span><span class="tok-n">setPageSize</span><span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">darea</span><span class="tok-p">.</span><span class="tok-n">allocatedHeight</span><span class="tok-p">.</span><span class="tok-kt">float</span><span class="tok-p">)</span>
<span class="tok-n">updateVal</span><span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">hadjustment</span><span class="tok-p">,</span> <span class="tok-n">dx</span><span class="tok-p">)</span>
<span class="tok-n">updateVal</span><span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">vadjustment</span><span class="tok-p">,</span> <span class="tok-n">dy</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">paint</span><span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">:</span> <span class="tok-n">PDA</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-c"># echo "paint"</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">save</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">translate</span><span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">hadjustment</span><span class="tok-p">.</span><span class="tok-n">upper</span> <span class="tok-o">*</span> <span class="tok-mf">0.5</span> <span class="tok-o">-</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">hadjustment</span><span class="tok-p">.</span><span class="tok-n">value</span><span class="tok-p">,</span> <span class="tok-c"># our origin is the center</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">vadjustment</span><span class="tok-p">.</span><span class="tok-n">upper</span> <span class="tok-o">*</span> <span class="tok-mf">0.5</span> <span class="tok-o">-</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">vadjustment</span><span class="tok-p">.</span><span class="tok-n">value</span><span class="tok-p">)</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">scale</span><span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">fullScale</span> <span class="tok-o">*</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">userZoom</span><span class="tok-p">,</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">fullScale</span> <span class="tok-o">*</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">userZoom</span><span class="tok-p">)</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">translate</span><span class="tok-p">(</span><span class="tok-o">-</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">dataX</span> <span class="tok-o">-</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">dataWidth</span> <span class="tok-o">*</span> <span class="tok-mf">0.5</span><span class="tok-p">,</span> <span class="tok-o">-</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">dataY</span> <span class="tok-o">-</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">dataHeight</span> <span class="tok-o">*</span> <span class="tok-mf">0.5</span><span class="tok-p">)</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">drawWorld</span><span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">cr</span><span class="tok-p">)</span> <span class="tok-c"># call the user provided drawing function</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">restore</span>
<span class="tok-k">proc </span><span class="tok-nf">dareaConfigureCallback</span><span class="tok-p">(</span><span class="tok-n">darea</span><span class="tok-p">:</span> <span class="tok-n">DrawingArea</span><span class="tok-p">;</span> <span class="tok-n">event</span><span class="tok-p">:</span> <span class="tok-n">EventConfigure</span><span class="tok-p">;</span> <span class="tok-n">this</span><span class="tok-p">:</span> <span class="tok-n">PDA</span><span class="tok-p">):</span> <span class="tok-kt">bool</span> <span class="tok-o">=</span>
<span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">dataX</span><span class="tok-p">,</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">dataY</span><span class="tok-p">,</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">dataWidth</span><span class="tok-p">,</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">dataHeight</span><span class="tok-p">)</span> <span class="tok-o">=</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">extents</span><span class="tok-p">()</span> <span class="tok-c"># query user defined size</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">fullScale</span> <span class="tok-o">=</span> <span class="tok-n">min</span><span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">darea</span><span class="tok-p">.</span><span class="tok-n">allocatedWidth</span><span class="tok-p">.</span><span class="tok-kt">float</span> <span class="tok-o">/</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">dataWidth</span><span class="tok-p">,</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">darea</span><span class="tok-p">.</span><span class="tok-n">allocatedHeight</span><span class="tok-p">.</span><span class="tok-kt">float</span> <span class="tok-o">/</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">dataHeight</span><span class="tok-p">)</span>
<span class="tok-k">if</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">surf</span> <span class="tok-o">!=</span> <span class="tok-kp">nil</span><span class="tok-p">:</span>
<span class="tok-n">destroy</span><span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">surf</span><span class="tok-p">)</span> <span class="tok-c"># manually destroy surface -- GC would do it for us, but GC is slow...</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">surf</span> <span class="tok-o">=</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">darea</span><span class="tok-p">.</span><span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">createSimilarSurface</span><span class="tok-p">(</span><span class="tok-n">Content</span><span class="tok-p">.</span><span class="tok-n">color</span><span class="tok-p">,</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">darea</span><span class="tok-p">.</span><span class="tok-n">allocatedWidth</span><span class="tok-p">,</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">darea</span><span class="tok-p">.</span><span class="tok-n">allocatedHeight</span><span class="tok-p">)</span>
<span class="tok-k">if</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">pattern</span> <span class="tok-o">!=</span> <span class="tok-kp">nil</span><span class="tok-p">:</span>
<span class="tok-n">patternDestroy</span><span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">pattern</span><span class="tok-p">)</span>
<span class="tok-k">if</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">cr</span> <span class="tok-o">!=</span> <span class="tok-kp">nil</span><span class="tok-p">:</span>
<span class="tok-n">destroy</span><span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">cr</span><span class="tok-p">)</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">pattern</span> <span class="tok-o">=</span> <span class="tok-n">patternCreateForSurface</span><span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">surf</span><span class="tok-p">)</span> <span class="tok-c"># pattern now owns the surface!</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">cr</span> <span class="tok-o">=</span> <span class="tok-n">newContext</span><span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">surf</span><span class="tok-p">)</span> <span class="tok-c"># this function references target!</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">paint</span>
<span class="tok-k">return</span> <span class="tok-n">gdk</span><span class="tok-p">.</span><span class="tok-n">EVENT_STOP</span>
<span class="tok-k">proc </span><span class="tok-nf">hscrollbarSizeAllocateCallback</span><span class="tok-p">(</span><span class="tok-n">s</span><span class="tok-p">:</span> <span class="tok-n">Scrollbar</span><span class="tok-p">;</span> <span class="tok-n">r</span><span class="tok-p">:</span> <span class="tok-n">gdk</span><span class="tok-p">.</span><span class="tok-n">Rectangle</span><span class="tok-p">;</span> <span class="tok-n">pda</span><span class="tok-p">:</span> <span class="tok-n">PDA</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">pda</span><span class="tok-p">.</span><span class="tok-n">hadjustment</span><span class="tok-p">.</span><span class="tok-n">setUpper</span><span class="tok-p">(</span><span class="tok-n">r</span><span class="tok-p">.</span><span class="tok-n">width</span><span class="tok-p">.</span><span class="tok-kt">float</span> <span class="tok-o">*</span> <span class="tok-n">pda</span><span class="tok-p">.</span><span class="tok-n">userZoom</span><span class="tok-p">)</span>
<span class="tok-n">pda</span><span class="tok-p">.</span><span class="tok-n">hadjustment</span><span class="tok-p">.</span><span class="tok-n">setPageSize</span><span class="tok-p">(</span><span class="tok-n">r</span><span class="tok-p">.</span><span class="tok-n">width</span><span class="tok-p">.</span><span class="tok-kt">float</span><span class="tok-p">)</span>
<span class="tok-k">if</span> <span class="tok-n">pda</span><span class="tok-p">.</span><span class="tok-n">oldSizeX</span> <span class="tok-o">!=</span> <span class="tok-mi">0</span><span class="tok-p">:</span> <span class="tok-c"># this fix is not exact, as fullScale can ...</span>
<span class="tok-n">updateVal</span><span class="tok-p">(</span><span class="tok-n">pda</span><span class="tok-p">.</span><span class="tok-n">hadjustment</span><span class="tok-p">,</span> <span class="tok-p">(</span><span class="tok-n">r</span><span class="tok-p">.</span><span class="tok-n">width</span> <span class="tok-o">-</span> <span class="tok-n">pda</span><span class="tok-p">.</span><span class="tok-n">oldSizeX</span><span class="tok-p">).</span><span class="tok-kt">float</span> <span class="tok-o">*</span> <span class="tok-mf">0.5</span><span class="tok-p">)</span>
<span class="tok-n">pda</span><span class="tok-p">.</span><span class="tok-n">oldSizeX</span> <span class="tok-o">=</span> <span class="tok-n">r</span><span class="tok-p">.</span><span class="tok-n">width</span>
<span class="tok-k">proc </span><span class="tok-nf">vscrollbarSizeAllocateCallback</span><span class="tok-p">(</span><span class="tok-n">s</span><span class="tok-p">:</span> <span class="tok-n">Scrollbar</span><span class="tok-p">;</span> <span class="tok-n">r</span><span class="tok-p">:</span> <span class="tok-n">gdk</span><span class="tok-p">.</span><span class="tok-n">Rectangle</span><span class="tok-p">;</span> <span class="tok-n">pda</span><span class="tok-p">:</span> <span class="tok-n">PDA</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">pda</span><span class="tok-p">.</span><span class="tok-n">vadjustment</span><span class="tok-p">.</span><span class="tok-n">setUpper</span><span class="tok-p">(</span><span class="tok-n">r</span><span class="tok-p">.</span><span class="tok-n">height</span><span class="tok-p">.</span><span class="tok-kt">float</span> <span class="tok-o">*</span> <span class="tok-n">pda</span><span class="tok-p">.</span><span class="tok-n">userZoom</span><span class="tok-p">)</span>
<span class="tok-n">pda</span><span class="tok-p">.</span><span class="tok-n">vadjustment</span><span class="tok-p">.</span><span class="tok-n">setPageSize</span><span class="tok-p">(</span><span class="tok-n">r</span><span class="tok-p">.</span><span class="tok-n">height</span><span class="tok-p">.</span><span class="tok-kt">float</span><span class="tok-p">)</span>
<span class="tok-k">if</span> <span class="tok-n">pda</span><span class="tok-p">.</span><span class="tok-n">oldSizeY</span> <span class="tok-o">!=</span> <span class="tok-mi">0</span><span class="tok-p">:</span> <span class="tok-c"># ... change when window is rezized. But it's good enough!</span>
<span class="tok-n">updateVal</span><span class="tok-p">(</span><span class="tok-n">pda</span><span class="tok-p">.</span><span class="tok-n">vadjustment</span><span class="tok-p">,</span> <span class="tok-p">(</span><span class="tok-n">r</span><span class="tok-p">.</span><span class="tok-n">height</span> <span class="tok-o">-</span> <span class="tok-n">pda</span><span class="tok-p">.</span><span class="tok-n">oldSizeY</span><span class="tok-p">).</span><span class="tok-kt">float</span> <span class="tok-o">*</span> <span class="tok-mf">0.5</span><span class="tok-p">)</span>
<span class="tok-n">pda</span><span class="tok-p">.</span><span class="tok-n">oldSizeY</span> <span class="tok-o">=</span> <span class="tok-n">r</span><span class="tok-p">.</span><span class="tok-n">height</span>
<span class="tok-k">proc </span><span class="tok-nf">updateAdjustmentsAndPaint</span><span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">:</span> <span class="tok-n">PDA</span><span class="tok-p">;</span> <span class="tok-n">dx</span><span class="tok-p">,</span> <span class="tok-n">dy</span><span class="tok-p">:</span> <span class="tok-kt">float</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">updateAdjustments</span><span class="tok-p">(</span><span class="tok-n">dx</span><span class="tok-p">,</span> <span class="tok-n">dy</span><span class="tok-p">)</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">paint</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">darea</span><span class="tok-p">.</span><span class="tok-n">queueDrawArea</span><span class="tok-p">(</span><span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">darea</span><span class="tok-p">.</span><span class="tok-n">allocatedWidth</span><span class="tok-p">,</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">darea</span><span class="tok-p">.</span><span class="tok-n">allocatedHeight</span><span class="tok-p">)</span>
<span class="tok-c"># event coordinates to user space</span>
<span class="tok-k">proc </span><span class="tok-nf">getUserCoordinates</span><span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">:</span> <span class="tok-n">PDA</span><span class="tok-p">;</span> <span class="tok-n">eventX</span><span class="tok-p">,</span> <span class="tok-n">eventY</span><span class="tok-p">:</span> <span class="tok-kt">float</span><span class="tok-p">):</span> <span class="tok-p">(</span><span class="tok-kt">float</span><span class="tok-p">,</span> <span class="tok-kt">float</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-p">((</span><span class="tok-n">eventX</span> <span class="tok-o">-</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">hadjustment</span><span class="tok-p">.</span><span class="tok-n">upper</span> <span class="tok-o">*</span> <span class="tok-mf">0.5</span> <span class="tok-o">+</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">hadjustment</span><span class="tok-p">.</span><span class="tok-n">value</span><span class="tok-p">)</span> <span class="tok-o">/</span> <span class="tok-p">(</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">fullScale</span> <span class="tok-o">*</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">userZoom</span><span class="tok-p">)</span> <span class="tok-o">+</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">dataX</span> <span class="tok-o">+</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">dataWidth</span> <span class="tok-o">*</span> <span class="tok-mf">0.5</span><span class="tok-p">,</span>
<span class="tok-p">(</span><span class="tok-n">eventY</span> <span class="tok-o">-</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">vadjustment</span><span class="tok-p">.</span><span class="tok-n">upper</span> <span class="tok-o">*</span> <span class="tok-mf">0.5</span> <span class="tok-o">+</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">vadjustment</span><span class="tok-p">.</span><span class="tok-n">value</span><span class="tok-p">)</span> <span class="tok-o">/</span> <span class="tok-p">(</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">fullScale</span> <span class="tok-o">*</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">userZoom</span><span class="tok-p">)</span> <span class="tok-o">+</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">dataY</span> <span class="tok-o">+</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">dataHeight</span> <span class="tok-o">*</span> <span class="tok-mf">0.5</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">onMotion</span><span class="tok-p">(</span><span class="tok-n">darea</span><span class="tok-p">:</span> <span class="tok-n">DrawingArea</span><span class="tok-p">;</span> <span class="tok-n">event</span><span class="tok-p">:</span> <span class="tok-n">EventMotion</span><span class="tok-p">;</span> <span class="tok-n">this</span><span class="tok-p">:</span> <span class="tok-n">PDA</span><span class="tok-p">):</span> <span class="tok-kt">bool</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">state</span> <span class="tok-o">=</span> <span class="tok-n">getState</span><span class="tok-p">(</span><span class="tok-n">event</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-p">(</span><span class="tok-n">x</span><span class="tok-p">,</span> <span class="tok-n">y</span><span class="tok-p">)</span> <span class="tok-o">=</span> <span class="tok-n">event</span><span class="tok-p">.</span><span class="tok-n">getCoords</span>
<span class="tok-k">if</span> <span class="tok-n">state</span><span class="tok-p">.</span><span class="tok-n">contains</span><span class="tok-p">(</span><span class="tok-n">button1</span><span class="tok-p">):</span> <span class="tok-c"># selecting</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">selecting</span> <span class="tok-o">=</span> <span class="tok-kp">true</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">zoomRectX1</span> <span class="tok-o">=</span> <span class="tok-n">x</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">zoomRectY1</span> <span class="tok-o">=</span> <span class="tok-n">y</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">darea</span><span class="tok-p">.</span><span class="tok-n">queueDrawArea</span><span class="tok-p">(</span><span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">darea</span><span class="tok-p">.</span><span class="tok-n">allocatedWidth</span><span class="tok-p">,</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">darea</span><span class="tok-p">.</span><span class="tok-n">allocatedHeight</span><span class="tok-p">)</span>
<span class="tok-k">elif</span> <span class="tok-n">button2</span> <span class="tok-ow">in</span> <span class="tok-n">state</span><span class="tok-p">:</span> <span class="tok-c"># panning</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">updateAdjustmentsAndPaint</span><span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">lastMousePosX</span> <span class="tok-o">-</span> <span class="tok-n">x</span><span class="tok-p">,</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">lastMousePosY</span> <span class="tok-o">-</span> <span class="tok-n">y</span><span class="tok-p">)</span>
<span class="tok-k">else</span><span class="tok-p">:</span>
<span class="tok-k">return</span> <span class="tok-n">gdk</span><span class="tok-p">.</span><span class="tok-n">EVENT_PROPAGATE</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">lastMousePosX</span> <span class="tok-o">=</span> <span class="tok-n">x</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">lastMousePosY</span> <span class="tok-o">=</span> <span class="tok-n">y</span>
<span class="tok-k">return</span> <span class="tok-n">gdk</span><span class="tok-p">.</span><span class="tok-n">EVENT_STOP</span>
<span class="tok-c">#event.request # request more motion events ?</span>
<span class="tok-c"># zooming with mouse wheel -- data near mouse pointer should not move if possible!</span>
<span class="tok-c"># hadjustment.value + event.x is the position in our zoomed_in world, (userZoom / z0 - 1)</span>
<span class="tok-c"># is the relative movement caused by zooming</span>
<span class="tok-c"># In other words, this is the delta-move d of a point at position P from zooming:</span>
<span class="tok-c"># d = newPos - P = P * scale - P = P * (z/z0) - P = P * (z/z0 - 1). We have to compensate for this d.</span>
<span class="tok-k">proc </span><span class="tok-nf">scrollEvent</span><span class="tok-p">(</span><span class="tok-n">darea</span><span class="tok-p">:</span> <span class="tok-n">DrawingArea</span><span class="tok-p">;</span> <span class="tok-n">event</span><span class="tok-p">:</span> <span class="tok-n">EventScroll</span><span class="tok-p">;</span> <span class="tok-n">this</span><span class="tok-p">:</span> <span class="tok-n">PDA</span><span class="tok-p">):</span> <span class="tok-kt">bool</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">z0</span> <span class="tok-o">=</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">userZoom</span>
<span class="tok-k">case</span> <span class="tok-n">getScrollDirection</span><span class="tok-p">(</span><span class="tok-n">event</span><span class="tok-p">)</span>
<span class="tok-k">of</span> <span class="tok-n">ScrollDirection</span><span class="tok-p">.</span><span class="tok-n">up</span><span class="tok-p">:</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">userZoom</span> <span class="tok-o">*=</span> <span class="tok-n">ZoomFactorMouseWheel</span>
<span class="tok-k">of</span> <span class="tok-n">ScrollDirection</span><span class="tok-p">.</span><span class="tok-n">down</span><span class="tok-p">:</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">userZoom</span> <span class="tok-o">/=</span> <span class="tok-n">ZoomFactorMouseWheel</span>
<span class="tok-k">if</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">userZoom</span> <span class="tok-o"><</span> <span class="tok-mi">1</span><span class="tok-p">:</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">userZoom</span> <span class="tok-o">=</span> <span class="tok-mi">1</span>
<span class="tok-k">else</span><span class="tok-p">:</span>
<span class="tok-k">return</span> <span class="tok-n">gdk</span><span class="tok-p">.</span><span class="tok-n">EVENT_PROPAGATE</span>
<span class="tok-k">if</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">zoomNearMousepointer</span><span class="tok-p">:</span>
<span class="tok-k">let</span> <span class="tok-p">(</span><span class="tok-n">x</span><span class="tok-p">,</span> <span class="tok-n">y</span><span class="tok-p">)</span> <span class="tok-o">=</span> <span class="tok-n">event</span><span class="tok-p">.</span><span class="tok-n">getCoords</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">updateAdjustmentsAndPaint</span><span class="tok-p">((</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">hadjustment</span><span class="tok-p">.</span><span class="tok-n">value</span> <span class="tok-o">+</span> <span class="tok-n">x</span><span class="tok-p">)</span> <span class="tok-o">*</span> <span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">userZoom</span> <span class="tok-o">/</span> <span class="tok-n">z0</span> <span class="tok-o">-</span> <span class="tok-mi">1</span><span class="tok-p">),</span>
<span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">vadjustment</span><span class="tok-p">.</span><span class="tok-n">value</span> <span class="tok-o">+</span> <span class="tok-n">y</span><span class="tok-p">)</span> <span class="tok-o">*</span> <span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">userZoom</span> <span class="tok-o">/</span> <span class="tok-n">z0</span> <span class="tok-o">-</span> <span class="tok-mi">1</span><span class="tok-p">))</span>
<span class="tok-k">else</span><span class="tok-p">:</span> <span class="tok-c"># zoom to center</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">updateAdjustmentsAndPaint</span><span class="tok-p">((</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">hadjustment</span><span class="tok-p">.</span><span class="tok-n">value</span> <span class="tok-o">+</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">darea</span><span class="tok-p">.</span><span class="tok-n">allocatedWidth</span><span class="tok-p">.</span><span class="tok-kt">float</span> <span class="tok-o">*</span> <span class="tok-mf">0.5</span><span class="tok-p">)</span> <span class="tok-o">*</span> <span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">userZoom</span> <span class="tok-o">/</span> <span class="tok-n">z0</span> <span class="tok-o">-</span> <span class="tok-mi">1</span><span class="tok-p">),</span>
<span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">vadjustment</span><span class="tok-p">.</span><span class="tok-n">value</span> <span class="tok-o">+</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">darea</span><span class="tok-p">.</span><span class="tok-n">allocatedHeight</span><span class="tok-p">.</span><span class="tok-kt">float</span> <span class="tok-o">*</span> <span class="tok-mf">0.5</span><span class="tok-p">)</span> <span class="tok-o">*</span> <span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">userZoom</span> <span class="tok-o">/</span> <span class="tok-n">z0</span> <span class="tok-o">-</span> <span class="tok-mi">1</span><span class="tok-p">))</span>
<span class="tok-k">return</span> <span class="tok-n">gdk</span><span class="tok-p">.</span><span class="tok-n">EVENT_STOP</span>
<span class="tok-k">proc </span><span class="tok-nf">buttonPressEvent</span><span class="tok-p">(</span><span class="tok-n">darea</span><span class="tok-p">:</span> <span class="tok-n">DrawingArea</span><span class="tok-p">;</span> <span class="tok-n">event</span><span class="tok-p">:</span> <span class="tok-n">EventButton</span><span class="tok-p">;</span> <span class="tok-n">this</span><span class="tok-p">:</span> <span class="tok-n">PDA</span><span class="tok-p">):</span> <span class="tok-kt">bool</span> <span class="tok-o">=</span>
<span class="tok-kd">var</span> <span class="tok-p">(</span><span class="tok-n">x</span><span class="tok-p">,</span> <span class="tok-n">y</span><span class="tok-p">)</span> <span class="tok-o">=</span> <span class="tok-n">event</span><span class="tok-p">.</span><span class="tok-n">getCoords</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">lastMousePosX</span> <span class="tok-o">=</span> <span class="tok-n">x</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">lastMousePosY</span> <span class="tok-o">=</span> <span class="tok-n">y</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">lastButtonDownPosX</span> <span class="tok-o">=</span> <span class="tok-n">x</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">lastButtonDownPosY</span> <span class="tok-o">=</span> <span class="tok-n">y</span>
<span class="tok-n">echo</span> <span class="tok-s">"buttonPressEvent"</span><span class="tok-p">,</span> <span class="tok-n">x</span><span class="tok-p">,</span> <span class="tok-s">" "</span><span class="tok-p">,</span> <span class="tok-n">y</span>
<span class="tok-p">(</span><span class="tok-n">x</span><span class="tok-p">,</span> <span class="tok-n">y</span><span class="tok-p">)</span> <span class="tok-o">=</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">getUserCoordinates</span><span class="tok-p">(</span><span class="tok-n">x</span><span class="tok-p">,</span> <span class="tok-n">y</span><span class="tok-p">)</span>
<span class="tok-n">echo</span> <span class="tok-s">"User coordinates: "</span><span class="tok-p">,</span> <span class="tok-n">x</span><span class="tok-p">,</span> <span class="tok-sc">' '</span><span class="tok-p">,</span> <span class="tok-n">y</span><span class="tok-p">,</span> <span class="tok-s">"</span><span class="tok-se">\n</span><span class="tok-s">"</span> <span class="tok-c"># to verify getUserCoordinates()</span>
<span class="tok-k">return</span> <span class="tok-n">gdk</span><span class="tok-p">.</span><span class="tok-n">EVENT_STOP</span>
<span class="tok-c"># zoom into selected rectangle and center it</span>
<span class="tok-c"># math: we first center the selection rectangle, and then compensate for translation due to scale</span>
<span class="tok-k">proc </span><span class="tok-nf">buttonReleaseEvent</span><span class="tok-p">(</span><span class="tok-n">darea</span><span class="tok-p">:</span> <span class="tok-n">DrawingArea</span><span class="tok-p">;</span> <span class="tok-n">event</span><span class="tok-p">:</span> <span class="tok-n">EventButton</span><span class="tok-p">;</span> <span class="tok-n">this</span><span class="tok-p">:</span> <span class="tok-n">PDA</span><span class="tok-p">):</span> <span class="tok-kt">bool</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-p">(</span><span class="tok-n">x</span><span class="tok-p">,</span> <span class="tok-n">y</span><span class="tok-p">)</span> <span class="tok-o">=</span> <span class="tok-n">event</span><span class="tok-p">.</span><span class="tok-n">getCoords</span>
<span class="tok-k">let</span> <span class="tok-n">b</span> <span class="tok-o">=</span> <span class="tok-n">getButton</span><span class="tok-p">(</span><span class="tok-n">event</span><span class="tok-p">)</span>
<span class="tok-k">if</span> <span class="tok-n">b</span> <span class="tok-o">==</span> <span class="tok-mi">1</span><span class="tok-p">:</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">selecting</span> <span class="tok-o">=</span> <span class="tok-kp">false</span>
<span class="tok-k">let</span> <span class="tok-n">z1</span> <span class="tok-o">=</span> <span class="tok-n">min</span><span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">darea</span><span class="tok-p">.</span><span class="tok-n">allocatedWidth</span><span class="tok-p">.</span><span class="tok-kt">float</span> <span class="tok-o">/</span> <span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">lastButtonDownPosX</span> <span class="tok-o">-</span> <span class="tok-n">x</span><span class="tok-p">).</span><span class="tok-n">abs</span><span class="tok-p">,</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">darea</span><span class="tok-p">.</span><span class="tok-n">allocatedHeight</span><span class="tok-p">.</span><span class="tok-kt">float</span> <span class="tok-o">/</span> <span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">lastButtonDownPosY</span> <span class="tok-o">-</span> <span class="tok-n">y</span><span class="tok-p">).</span><span class="tok-n">abs</span><span class="tok-p">)</span>
<span class="tok-k">if</span> <span class="tok-n">z1</span> <span class="tok-o"><</span> <span class="tok-n">ZoomFactorSelectMax</span><span class="tok-p">:</span> <span class="tok-c"># else selection rectangle will persist, we may output a message...</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">userZoom</span> <span class="tok-o">*=</span> <span class="tok-n">z1</span>
<span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">updateAdjustmentsAndPaint</span><span class="tok-p">(</span>
<span class="tok-p">((</span><span class="tok-n">x</span> <span class="tok-o">+</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">lastButtonDownPosX</span><span class="tok-p">)</span> <span class="tok-o">*</span> <span class="tok-n">z1</span> <span class="tok-o">-</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">darea</span><span class="tok-p">.</span><span class="tok-n">allocatedWidth</span><span class="tok-p">.</span><span class="tok-kt">float</span><span class="tok-p">)</span> <span class="tok-o">*</span> <span class="tok-mf">0.5</span> <span class="tok-o">+</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">hadjustment</span><span class="tok-p">.</span><span class="tok-n">value</span> <span class="tok-o">*</span> <span class="tok-p">(</span><span class="tok-n">z1</span> <span class="tok-o">-</span> <span class="tok-mi">1</span><span class="tok-p">),</span>
<span class="tok-p">((</span><span class="tok-n">y</span> <span class="tok-o">+</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">lastButtonDownPosY</span><span class="tok-p">)</span> <span class="tok-o">*</span> <span class="tok-n">z1</span> <span class="tok-o">-</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">darea</span><span class="tok-p">.</span><span class="tok-n">allocatedHeight</span><span class="tok-p">.</span><span class="tok-kt">float</span><span class="tok-p">)</span> <span class="tok-o">*</span> <span class="tok-mf">0.5</span> <span class="tok-o">+</span> <span class="tok-n">this</span><span class="tok-p">.</span><span class="tok-n">vadjustment</span><span class="tok-p">.</span><span class="tok-n">value</span> <span class="tok-o">*</span> <span class="tok-p">(</span><span class="tok-n">z1</span> <span class="tok-o">-</span> <span class="tok-mi">1</span><span class="tok-p">))</span>
<span class="tok-k">return</span> <span class="tok-n">gdk</span><span class="tok-p">.</span><span class="tok-n">EVENT_STOP</span>
<span class="tok-k">return</span> <span class="tok-n">gdk</span><span class="tok-p">.</span><span class="tok-n">EVENT_PROPAGATE</span>
<span class="tok-k">proc </span><span class="tok-nf">onAdjustmentEvent</span><span class="tok-p">(</span><span class="tok-n">this</span><span class="tok-p">:</span> <span class="tok-n">PosAdj</span><span class="tok-p">;</span> <span class="tok-n">pda</span><span class="tok-p">:</span> <span class="tok-n">PDA</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">pda</span><span class="tok-p">.</span><span class="tok-n">paint</span>
<span class="tok-n">pda</span><span class="tok-p">.</span><span class="tok-n">darea</span><span class="tok-p">.</span><span class="tok-n">queueDrawArea</span><span class="tok-p">(</span><span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-n">pda</span><span class="tok-p">.</span><span class="tok-n">darea</span><span class="tok-p">.</span><span class="tok-n">allocatedWidth</span><span class="tok-p">,</span> <span class="tok-n">pda</span><span class="tok-p">.</span><span class="tok-n">darea</span><span class="tok-p">.</span><span class="tok-n">allocatedHeight</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">newPDA</span><span class="tok-p">:</span> <span class="tok-n">PDA</span> <span class="tok-o">=</span>
<span class="tok-n">initGrid</span><span class="tok-p">(</span><span class="tok-n">result</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">da</span> <span class="tok-o">=</span> <span class="tok-n">newDrawingArea</span><span class="tok-p">()</span>
<span class="tok-n">result</span><span class="tok-p">.</span><span class="tok-n">darea</span> <span class="tok-o">=</span> <span class="tok-n">da</span>
<span class="tok-n">da</span><span class="tok-p">.</span><span class="tok-n">setHExpand</span>
<span class="tok-n">da</span><span class="tok-p">.</span><span class="tok-n">setVExpand</span>
<span class="tok-n">da</span><span class="tok-p">.</span><span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-s">"draw"</span><span class="tok-p">,</span> <span class="tok-n">drawingAreaDrawCb</span><span class="tok-p">,</span> <span class="tok-n">result</span><span class="tok-p">)</span>
<span class="tok-n">da</span><span class="tok-p">.</span><span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-s">"configure-event"</span><span class="tok-p">,</span> <span class="tok-n">dareaConfigureCallback</span><span class="tok-p">,</span> <span class="tok-n">result</span><span class="tok-p">)</span>
<span class="tok-n">da</span><span class="tok-p">.</span><span class="tok-n">addEvents</span><span class="tok-p">({</span><span class="tok-n">EventFlag</span><span class="tok-p">.</span><span class="tok-n">buttonPress</span><span class="tok-p">,</span> <span class="tok-n">EventFlag</span><span class="tok-p">.</span><span class="tok-n">buttonRelease</span><span class="tok-p">,</span>
<span class="tok-n">EventFlag</span><span class="tok-p">.</span><span class="tok-n">scroll</span><span class="tok-p">,</span> <span class="tok-n">button1Motion</span><span class="tok-p">,</span> <span class="tok-n">button2Motion</span><span class="tok-p">,</span> <span class="tok-n">pointerMotionHint</span><span class="tok-p">})</span>
<span class="tok-n">da</span><span class="tok-p">.</span><span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-s">"motion-notify-event"</span><span class="tok-p">,</span> <span class="tok-n">onMotion</span><span class="tok-p">,</span> <span class="tok-n">result</span><span class="tok-p">)</span>
<span class="tok-n">da</span><span class="tok-p">.</span><span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-s">"scroll_event"</span><span class="tok-p">,</span> <span class="tok-n">scrollEvent</span><span class="tok-p">,</span> <span class="tok-n">result</span><span class="tok-p">)</span>
<span class="tok-n">da</span><span class="tok-p">.</span><span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-s">"button_press_event"</span><span class="tok-p">,</span> <span class="tok-n">buttonPressEvent</span><span class="tok-p">,</span> <span class="tok-n">result</span><span class="tok-p">)</span>
<span class="tok-n">da</span><span class="tok-p">.</span><span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-s">"button_release_event"</span><span class="tok-p">,</span> <span class="tok-n">buttonReleaseEvent</span><span class="tok-p">,</span> <span class="tok-n">result</span><span class="tok-p">)</span>
<span class="tok-n">result</span><span class="tok-p">.</span><span class="tok-n">zoomNearMousepointer</span> <span class="tok-o">=</span> <span class="tok-n">ZoomNearMousepointer</span> <span class="tok-c"># mouse wheel zooming</span>
<span class="tok-n">result</span><span class="tok-p">.</span><span class="tok-n">userZoom</span> <span class="tok-o">=</span> <span class="tok-mf">1.0</span>
<span class="tok-n">result</span><span class="tok-p">.</span><span class="tok-n">hadjustment</span> <span class="tok-o">=</span> <span class="tok-n">newPosAdj</span><span class="tok-p">()</span>
<span class="tok-n">result</span><span class="tok-p">.</span><span class="tok-n">hadjustment</span><span class="tok-p">.</span><span class="tok-n">handlerID</span> <span class="tok-o">=</span> <span class="tok-n">result</span><span class="tok-p">.</span><span class="tok-n">hadjustment</span><span class="tok-p">.</span><span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-s">"value-changed"</span><span class="tok-p">,</span> <span class="tok-n">onAdjustmentEvent</span><span class="tok-p">,</span> <span class="tok-n">result</span><span class="tok-p">)</span>
<span class="tok-n">result</span><span class="tok-p">.</span><span class="tok-n">vadjustment</span> <span class="tok-o">=</span> <span class="tok-n">newPosAdj</span><span class="tok-p">()</span>
<span class="tok-n">result</span><span class="tok-p">.</span><span class="tok-n">vadjustment</span><span class="tok-p">.</span><span class="tok-n">handlerID</span> <span class="tok-o">=</span> <span class="tok-n">result</span><span class="tok-p">.</span><span class="tok-n">vadjustment</span><span class="tok-p">.</span><span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-s">"value-changed"</span><span class="tok-p">,</span> <span class="tok-n">onAdjustmentEvent</span><span class="tok-p">,</span> <span class="tok-n">result</span><span class="tok-p">)</span>
<span class="tok-n">result</span><span class="tok-p">.</span><span class="tok-n">hscrollbar</span> <span class="tok-o">=</span> <span class="tok-n">newScrollbar</span><span class="tok-p">(</span><span class="tok-n">Orientation</span><span class="tok-p">.</span><span class="tok-n">horizontal</span><span class="tok-p">,</span> <span class="tok-n">result</span><span class="tok-p">.</span><span class="tok-n">hadjustment</span><span class="tok-p">)</span>
<span class="tok-n">result</span><span class="tok-p">.</span><span class="tok-n">vscrollbar</span> <span class="tok-o">=</span> <span class="tok-n">newScrollbar</span><span class="tok-p">(</span><span class="tok-n">Orientation</span><span class="tok-p">.</span><span class="tok-n">vertical</span><span class="tok-p">,</span> <span class="tok-n">result</span><span class="tok-p">.</span><span class="tok-n">vadjustment</span><span class="tok-p">)</span>
<span class="tok-n">result</span><span class="tok-p">.</span><span class="tok-n">hscrollbar</span><span class="tok-p">.</span><span class="tok-n">setHExpand</span>
<span class="tok-n">result</span><span class="tok-p">.</span><span class="tok-n">vscrollbar</span><span class="tok-p">.</span><span class="tok-n">setVExpand</span>
<span class="tok-n">result</span><span class="tok-p">.</span><span class="tok-n">hscrollbar</span><span class="tok-p">.</span><span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-s">"size-allocate"</span><span class="tok-p">,</span> <span class="tok-n">hscrollbarSizeAllocateCallback</span><span class="tok-p">,</span> <span class="tok-n">result</span><span class="tok-p">)</span>
<span class="tok-n">result</span><span class="tok-p">.</span><span class="tok-n">vscrollbar</span><span class="tok-p">.</span><span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-s">"size-allocate"</span><span class="tok-p">,</span> <span class="tok-n">vscrollbarSizeAllocateCallback</span><span class="tok-p">,</span> <span class="tok-n">result</span><span class="tok-p">)</span>
<span class="tok-n">result</span><span class="tok-p">.</span><span class="tok-n">attach</span><span class="tok-p">(</span><span class="tok-n">result</span><span class="tok-p">.</span><span class="tok-n">darea</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">)</span>
<span class="tok-n">result</span><span class="tok-p">.</span><span class="tok-n">attach</span><span class="tok-p">(</span><span class="tok-n">result</span><span class="tok-p">.</span><span class="tok-n">vscrollbar</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">)</span>
<span class="tok-n">result</span><span class="tok-p">.</span><span class="tok-n">attach</span><span class="tok-p">(</span><span class="tok-n">result</span><span class="tok-p">.</span><span class="tok-n">hscrollbar</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">appStartup</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">:</span> <span class="tok-n">Application</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">echo</span> <span class="tok-s">"appStartup"</span>
<span class="tok-k">proc </span><span class="tok-nf">appActivate</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">:</span> <span class="tok-n">Application</span><span class="tok-p">;</span> <span class="tok-n">initData</span><span class="tok-p">:</span> <span class="tok-n">PDA_Data</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">window</span> <span class="tok-o">=</span> <span class="tok-n">newApplicationWindow</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">title</span> <span class="tok-o">=</span> <span class="tok-s">"Drawing example"</span>
<span class="tok-c"># window.defaultSize = initData.windowSize</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">defaultSize</span> <span class="tok-o">=</span> <span class="tok-p">(</span><span class="tok-n">initData</span><span class="tok-p">.</span><span class="tok-n">windowSize</span><span class="tok-o">[</span><span class="tok-mi">0</span><span class="tok-o">]</span><span class="tok-p">,</span> <span class="tok-n">initData</span><span class="tok-p">.</span><span class="tok-n">windowSize</span><span class="tok-o">[</span><span class="tok-mi">1</span><span class="tok-o">]</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">pda</span> <span class="tok-o">=</span> <span class="tok-n">newPDA</span><span class="tok-p">()</span>
<span class="tok-n">pda</span><span class="tok-p">.</span><span class="tok-n">drawWorld</span> <span class="tok-o">=</span> <span class="tok-n">initData</span><span class="tok-p">.</span><span class="tok-n">draw</span>
<span class="tok-n">pda</span><span class="tok-p">.</span><span class="tok-n">extents</span> <span class="tok-o">=</span> <span class="tok-n">initData</span><span class="tok-p">.</span><span class="tok-n">extents</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">add</span><span class="tok-p">(</span><span class="tok-n">pda</span><span class="tok-p">)</span>
<span class="tok-n">showAll</span><span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">newDisplay</span><span class="tok-o">*</span><span class="tok-p">(</span><span class="tok-n">initData</span><span class="tok-p">:</span> <span class="tok-n">PDA_Data</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">app</span> <span class="tok-o">=</span> <span class="tok-n">newApplication</span><span class="tok-p">(</span><span class="tok-s">"org.gtk.example"</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">,</span> <span class="tok-s">"startup"</span><span class="tok-p">,</span> <span class="tok-n">appStartup</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">,</span> <span class="tok-s">"activate"</span><span class="tok-p">,</span> <span class="tok-n">appActivate</span><span class="tok-p">,</span> <span class="tok-n">initData</span><span class="tok-p">)</span>
<span class="tok-k">discard</span> <span class="tok-n">run</span><span class="tok-p">(</span><span class="tok-n">app</span><span class="tok-p">)</span>
<span class="tok-k">when</span> <span class="tok-n">isMainModule</span><span class="tok-p">:</span>
<span class="tok-k">const</span> <span class="tok-c"># arbitrary locations for our data</span>
<span class="tok-n">DataX</span> <span class="tok-o">=</span> <span class="tok-mf">150.0</span>
<span class="tok-n">DataY</span> <span class="tok-o">=</span> <span class="tok-mf">250.0</span>
<span class="tok-n">DataWidth</span> <span class="tok-o">=</span> <span class="tok-mf">200.0</span>
<span class="tok-n">DataHeight</span> <span class="tok-o">=</span> <span class="tok-mf">120.0</span>
<span class="tok-c"># we need two user defined functions -- one gives the extent of the graphics,</span>
<span class="tok-c"># and the other does the cairo drawing using a cairo context.</span>
<span class="tok-c"># bounding box of user data -- x, y, w, h -- top left corner, width, height</span>
<span class="tok-k">proc </span><span class="tok-nf">worldExtents</span><span class="tok-p">():</span> <span class="tok-p">(</span><span class="tok-kt">float</span><span class="tok-p">,</span> <span class="tok-kt">float</span><span class="tok-p">,</span> <span class="tok-kt">float</span><span class="tok-p">,</span> <span class="tok-kt">float</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-p">(</span><span class="tok-n">DataX</span><span class="tok-p">,</span> <span class="tok-n">DataY</span><span class="tok-p">,</span> <span class="tok-n">DataWidth</span><span class="tok-p">,</span> <span class="tok-n">DataHeight</span><span class="tok-p">)</span> <span class="tok-c"># current extents of our user world</span>
<span class="tok-c"># draw to cairo context</span>
<span class="tok-k">proc </span><span class="tok-nf">drawWorld</span><span class="tok-p">(</span><span class="tok-n">cr</span><span class="tok-p">:</span> <span class="tok-n">cairo</span><span class="tok-p">.</span><span class="tok-n">Context</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">setSource</span><span class="tok-p">(</span><span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">)</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">paint</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">setSource</span><span class="tok-p">(</span><span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">)</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">setLineWidth</span><span class="tok-p">(</span><span class="tok-mi">2</span><span class="tok-p">)</span>
<span class="tok-kd">var</span> <span class="tok-n">i</span> <span class="tok-o">=</span> <span class="tok-mf">0.0</span>
<span class="tok-k">while</span> <span class="tok-n">min</span><span class="tok-p">(</span><span class="tok-n">DataWidth</span> <span class="tok-o">-</span> <span class="tok-mi">2</span> <span class="tok-o">*</span> <span class="tok-n">i</span><span class="tok-p">,</span> <span class="tok-n">DataHeight</span> <span class="tok-o">-</span> <span class="tok-mi">2</span> <span class="tok-o">*</span> <span class="tok-n">i</span><span class="tok-p">)</span> <span class="tok-o">></span> <span class="tok-mi">0</span><span class="tok-p">:</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">rectangle</span><span class="tok-p">(</span><span class="tok-n">DataX</span> <span class="tok-o">+</span> <span class="tok-n">i</span><span class="tok-p">,</span> <span class="tok-n">DataY</span> <span class="tok-o">+</span> <span class="tok-n">i</span><span class="tok-p">,</span> <span class="tok-n">DataWidth</span> <span class="tok-o">-</span> <span class="tok-mi">2</span> <span class="tok-o">*</span> <span class="tok-n">i</span><span class="tok-p">,</span> <span class="tok-n">DataHeight</span> <span class="tok-o">-</span> <span class="tok-mi">2</span> <span class="tok-o">*</span> <span class="tok-n">i</span><span class="tok-p">)</span>
<span class="tok-n">i</span> <span class="tok-o">+=</span> <span class="tok-mi">10</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">stroke</span>
<span class="tok-k">proc </span><span class="tok-nf">test</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">data</span> <span class="tok-o">=</span> <span class="tok-n">PDA_Data</span><span class="tok-p">(</span><span class="tok-n">draw</span><span class="tok-p">:</span> <span class="tok-n">drawWorld</span><span class="tok-p">,</span> <span class="tok-n">extents</span><span class="tok-p">:</span> <span class="tok-n">worldExtents</span><span class="tok-p">,</span> <span class="tok-n">windowSize</span><span class="tok-p">:</span> <span class="tok-p">(</span><span class="tok-mi">800</span><span class="tok-p">,</span> <span class="tok-mi">600</span><span class="tok-p">))</span>
<span class="tok-n">newDisplay</span><span class="tok-p">(</span><span class="tok-n">data</span><span class="tok-p">)</span>
<span class="tok-n">test</span><span class="tok-p">()</span> <span class="tok-c"># 337 lines</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>We can use this module as a library easily and get this simple drawing tool with full zoom and scroll support:</p>
</div>
<div id="darea_test.nim" class="listingblock">
<div class="title">darea_test.nim</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="nim"><span></span><span class="tok-kn">import</span> <span class="tok-n">gintro</span><span class="tok-o">/</span><span class="tok-n">cairo</span>
<span class="tok-kn">import</span> <span class="tok-n">drawingarea</span>
<span class="tok-kn">from</span> <span class="tok-n">math</span> <span class="tok-kn">import</span> <span class="tok-n">PI</span>
<span class="tok-k">proc </span><span class="tok-nf">extents</span><span class="tok-p">():</span> <span class="tok-p">(</span><span class="tok-kt">float</span><span class="tok-p">,</span> <span class="tok-kt">float</span><span class="tok-p">,</span> <span class="tok-kt">float</span><span class="tok-p">,</span> <span class="tok-kt">float</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-p">(</span><span class="tok-mf">0.0</span><span class="tok-p">,</span> <span class="tok-mf">0.0</span><span class="tok-p">,</span> <span class="tok-mf">100.0</span><span class="tok-p">,</span> <span class="tok-mf">100.0</span><span class="tok-p">)</span> <span class="tok-c"># ugly float literals</span>
<span class="tok-c"># draw to cairo context</span>
<span class="tok-k">proc </span><span class="tok-nf">draw</span><span class="tok-p">(</span><span class="tok-n">cr</span><span class="tok-p">:</span> <span class="tok-n">cairo</span><span class="tok-p">.</span><span class="tok-n">Context</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">setSource</span><span class="tok-p">(</span><span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">)</span> <span class="tok-c"># set background color and paint</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">paint</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">setSource</span><span class="tok-p">(</span><span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">)</span> <span class="tok-c"># forground color</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">arc</span><span class="tok-p">(</span><span class="tok-mi">20</span><span class="tok-p">,</span> <span class="tok-mi">30</span><span class="tok-p">,</span> <span class="tok-mi">10</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">5</span><span class="tok-p">)</span> <span class="tok-c"># nearly a circle</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">newSubPath</span> <span class="tok-c"># do not join the two arcs</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">arc</span><span class="tok-p">(</span><span class="tok-mi">70</span><span class="tok-p">,</span> <span class="tok-mi">60</span><span class="tok-p">,</span> <span class="tok-mi">20</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-n">math</span><span class="tok-p">.</span><span class="tok-n">PI</span><span class="tok-p">)</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">stroke</span> <span class="tok-c"># finally do it</span>
<span class="tok-k">proc </span><span class="tok-nf">main</span> <span class="tok-o">=</span>
<span class="tok-kd">var</span> <span class="tok-n">data</span><span class="tok-p">:</span> <span class="tok-n">PDA_Data</span>
<span class="tok-n">data</span><span class="tok-p">.</span><span class="tok-n">draw</span> <span class="tok-o">=</span> <span class="tok-n">draw</span>
<span class="tok-n">data</span><span class="tok-p">.</span><span class="tok-n">extents</span> <span class="tok-o">=</span> <span class="tok-n">extents</span>
<span class="tok-n">data</span><span class="tok-p">.</span><span class="tok-n">windowSize</span> <span class="tok-o">=</span> <span class="tok-p">(</span><span class="tok-mi">800</span><span class="tok-p">,</span> <span class="tok-mi">600</span><span class="tok-p">)</span>
<span class="tok-n">newDisplay</span><span class="tok-p">(</span><span class="tok-n">data</span><span class="tok-p">)</span>
<span class="tok-n">main</span><span class="tok-p">()</span></code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_one_more_cairo_example">One more cairo example</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Recently Mr. C. Eric Cashon provided an example code for working with a large bitmap image.
His example writes the image to disk, loads it again and displays the image allowing
zooming and translation. As examples are rare in these days, and that example is not to large,
I used c2nim to convert it to Nim. Below is the code with a few manually fixes. Note, the
current shipped cairo.nim module contains an assert statement, which prevents running this example.
If you really intent running this code, you will have to fix that single line in cairo.nim. I
have to do some more fixes in the cairo module and may ship a new version eventually. This
example is really low level, as alloc() is used directly.</p>
</div>
<div id="cairoImage.nim" class="listingblock">
<div class="title">cairoImage.nim</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="nim"><span></span><span class="tok-c"># https://discourse.gnome.org/t/proper-zoom-pan-image-approach-for-large-images/1497/6</span>
<span class="tok-c"># Nim version of the C example of C. Eric Cashon</span>
<span class="tok-kn">import</span> <span class="tok-n">gintro</span><span class="tok-o">/[</span><span class="tok-n">gtk</span><span class="tok-p">,</span> <span class="tok-n">gobject</span><span class="tok-p">,</span> <span class="tok-n">glib</span><span class="tok-p">,</span> <span class="tok-n">cairo</span><span class="tok-o">]</span>
<span class="tok-kn">from</span> <span class="tok-n">math</span> <span class="tok-kn">import</span> <span class="tok-n">TAU</span>
<span class="tok-kn">import</span> <span class="tok-n">strutils</span>
<span class="tok-k">const</span>
<span class="tok-n">Width</span> <span class="tok-o">=</span> <span class="tok-mi">5000</span>
<span class="tok-n">Height</span> <span class="tok-o">=</span> <span class="tok-mi">5000</span>
<span class="tok-n">CFormat</span> <span class="tok-o">=</span> <span class="tok-n">cairo</span><span class="tok-p">.</span><span class="tok-n">Format</span><span class="tok-p">.</span><span class="tok-n">argb32</span>
<span class="tok-kd">var</span>
<span class="tok-n">Key</span><span class="tok-p">:</span> <span class="tok-n">cairo</span><span class="tok-p">.</span><span class="tok-n">UserDataKey</span>
<span class="tok-n">translateX</span><span class="tok-p">:</span> <span class="tok-kt">float</span>
<span class="tok-n">translateY</span><span class="tok-p">:</span> <span class="tok-kt">float</span>
<span class="tok-n">scale</span> <span class="tok-o">=</span> <span class="tok-mf">1.0</span>
<span class="tok-sd">## Store data from file.</span>
<span class="tok-n">bigSurfaceData</span><span class="tok-o">*</span><span class="tok-p">:</span> <span class="tok-k">ptr</span> <span class="tok-n">cuchar</span> <span class="tok-o">=</span> <span class="tok-kp">nil</span>
<span class="tok-k">proc </span><span class="tok-nf">translateXSpinChanged</span><span class="tok-p">(</span><span class="tok-n">spinButton</span><span class="tok-p">:</span> <span class="tok-n">SpinButton</span><span class="tok-p">;</span> <span class="tok-n">data</span><span class="tok-p">:</span> <span class="tok-n">DrawingArea</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">translateX</span> <span class="tok-o">=</span> <span class="tok-n">spinButton</span><span class="tok-p">.</span><span class="tok-n">value</span>
<span class="tok-n">data</span><span class="tok-p">.</span><span class="tok-n">queueDraw</span>
<span class="tok-k">proc </span><span class="tok-nf">translateYSpinChanged</span><span class="tok-p">(</span><span class="tok-n">spinButton</span><span class="tok-p">:</span> <span class="tok-n">SpinButton</span><span class="tok-p">;</span> <span class="tok-n">data</span><span class="tok-p">:</span> <span class="tok-n">DrawingArea</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">translateY</span> <span class="tok-o">=</span> <span class="tok-n">spinButton</span><span class="tok-p">.</span><span class="tok-n">getValue</span>
<span class="tok-n">data</span><span class="tok-p">.</span><span class="tok-n">queueDraw</span>
<span class="tok-k">proc </span><span class="tok-nf">scaleSpinChanged</span><span class="tok-p">(</span><span class="tok-n">spinButton</span><span class="tok-p">:</span> <span class="tok-n">SpinButton</span><span class="tok-p">;</span> <span class="tok-n">data</span><span class="tok-p">:</span> <span class="tok-n">DrawingArea</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">scale</span> <span class="tok-o">=</span> <span class="tok-n">spinButton</span><span class="tok-p">.</span><span class="tok-n">value</span>
<span class="tok-n">data</span><span class="tok-p">.</span><span class="tok-n">queueDraw</span>
<span class="tok-k">proc </span><span class="tok-nf">saveBigSurface</span> <span class="tok-o">=</span>
<span class="tok-sd">## Use gdk_cairo_surface_create_from_pixbuf() to read in a pixbuf. Try a test surface here.</span>
<span class="tok-k">let</span> <span class="tok-n">bigSurface</span> <span class="tok-o">=</span> <span class="tok-n">imageSurfaceCreate</span><span class="tok-p">(</span><span class="tok-n">CFormat</span><span class="tok-p">,</span> <span class="tok-n">Width</span><span class="tok-p">,</span> <span class="tok-n">Height</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">cr</span> <span class="tok-o">=</span> <span class="tok-n">newContext</span><span class="tok-p">(</span><span class="tok-n">bigSurface</span><span class="tok-p">)</span>
<span class="tok-sd">## Paint the background.</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">setSource</span><span class="tok-p">(</span><span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">)</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">paint</span>
<span class="tok-sd">## Draw a circle.</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">setSource</span><span class="tok-p">(</span><span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">)</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">arc</span><span class="tok-p">(</span><span class="tok-mi">250</span><span class="tok-p">,</span> <span class="tok-mi">250</span><span class="tok-p">,</span> <span class="tok-mi">50</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-n">math</span><span class="tok-p">.</span><span class="tok-n">TAU</span><span class="tok-p">)</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">fill</span>
<span class="tok-sd">## Draw some test grid lines.</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">setSource</span><span class="tok-p">(</span><span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">)</span>
<span class="tok-k">for</span> <span class="tok-n">i</span> <span class="tok-ow">in</span> <span class="tok-n">countup</span><span class="tok-p">(</span><span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">4900</span><span class="tok-p">,</span> <span class="tok-mi">100</span><span class="tok-p">):</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">moveTo</span><span class="tok-p">(</span><span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-n">i</span><span class="tok-p">.</span><span class="tok-kt">float</span><span class="tok-p">)</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">lineTo</span><span class="tok-p">(</span><span class="tok-mi">5000</span><span class="tok-p">,</span> <span class="tok-n">i</span><span class="tok-p">.</span><span class="tok-kt">float</span><span class="tok-p">)</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">stroke</span>
<span class="tok-k">for</span> <span class="tok-n">i</span> <span class="tok-ow">in</span> <span class="tok-n">countup</span><span class="tok-p">(</span><span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">4900</span><span class="tok-p">,</span> <span class="tok-mi">100</span><span class="tok-p">):</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">moveTo</span><span class="tok-p">(</span><span class="tok-n">i</span><span class="tok-p">.</span><span class="tok-kt">float</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">)</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">lineTo</span><span class="tok-p">(</span><span class="tok-n">i</span><span class="tok-p">.</span><span class="tok-kt">float</span><span class="tok-p">,</span> <span class="tok-mi">5000</span><span class="tok-p">)</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">stroke</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">setSource</span><span class="tok-p">(</span><span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">)</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">setLineWidth</span><span class="tok-p">(</span><span class="tok-mi">10</span><span class="tok-p">)</span>
<span class="tok-k">for</span> <span class="tok-n">i</span> <span class="tok-ow">in</span> <span class="tok-mi">0</span> <span class="tok-p">..</span><span class="tok-o"><</span> <span class="tok-mi">10</span><span class="tok-p">:</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">moveTo</span><span class="tok-p">(</span><span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-n">i</span><span class="tok-p">.</span><span class="tok-kt">float</span> <span class="tok-o">*</span> <span class="tok-mf">500.0</span><span class="tok-p">)</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">lineTo</span><span class="tok-p">(</span><span class="tok-mi">5000</span><span class="tok-p">,</span> <span class="tok-n">i</span><span class="tok-p">.</span><span class="tok-kt">float</span> <span class="tok-o">*</span> <span class="tok-mf">500.0</span><span class="tok-p">)</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">stroke</span>
<span class="tok-k">for</span> <span class="tok-n">i</span> <span class="tok-ow">in</span> <span class="tok-mi">0</span> <span class="tok-p">..</span><span class="tok-o"><</span> <span class="tok-mi">10</span><span class="tok-p">:</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">moveTo</span><span class="tok-p">(</span><span class="tok-n">i</span><span class="tok-p">.</span><span class="tok-kt">float</span> <span class="tok-o">*</span> <span class="tok-mf">500.0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">)</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">lineTo</span><span class="tok-p">(</span><span class="tok-n">i</span><span class="tok-p">.</span><span class="tok-kt">float</span> <span class="tok-o">*</span> <span class="tok-mf">500.0</span><span class="tok-p">,</span> <span class="tok-mi">5000</span><span class="tok-p">)</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">stroke</span>
<span class="tok-sd">## Outside box.</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">setLineWidth</span><span class="tok-p">(</span><span class="tok-mi">20</span><span class="tok-p">)</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">setSource</span><span class="tok-p">(</span><span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">)</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">rectangle</span><span class="tok-p">(</span><span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">5000</span><span class="tok-p">,</span> <span class="tok-mi">5000</span><span class="tok-p">)</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">stroke</span>
<span class="tok-sd">## Save surface data to file.</span>
<span class="tok-k">let</span> <span class="tok-n">f</span><span class="tok-p">:</span> <span class="tok-n">File</span> <span class="tok-o">=</span> <span class="tok-n">open</span><span class="tok-p">(</span><span class="tok-s">"big_surface.s"</span><span class="tok-p">,</span> <span class="tok-n">fmWrite</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">p</span><span class="tok-p">:</span> <span class="tok-k">ptr</span> <span class="tok-n">cuchar</span> <span class="tok-o">=</span> <span class="tok-n">cairo_image_surface_get_data</span><span class="tok-p">(</span><span class="tok-n">bigSurface</span><span class="tok-p">.</span><span class="tok-n">impl</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">len</span> <span class="tok-o">=</span> <span class="tok-n">writeBuffer</span><span class="tok-p">(</span><span class="tok-n">f</span><span class="tok-p">,</span> <span class="tok-n">p</span><span class="tok-p">,</span> <span class="tok-n">cairo_format_stride_for_width</span><span class="tok-p">(</span><span class="tok-n">CFormat</span><span class="tok-p">,</span> <span class="tok-n">Width</span><span class="tok-p">)</span> <span class="tok-o">*</span> <span class="tok-n">Height</span><span class="tok-p">)</span>
<span class="tok-n">echo</span><span class="tok-p">(</span><span class="tok-s">"write </span><span class="tok-si">$1</span><span class="tok-se">\n</span><span class="tok-s">"</span> <span class="tok-o">%</span> <span class="tok-o">$</span><span class="tok-n">len</span><span class="tok-p">)</span>
<span class="tok-n">close</span><span class="tok-p">(</span><span class="tok-n">f</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">myDealloc</span><span class="tok-p">(</span><span class="tok-n">data</span><span class="tok-p">:</span> <span class="tok-n">pointer</span><span class="tok-p">)</span> <span class="tok-p">{.</span><span class="tok-n">cdecl</span><span class="tok-p">.}</span> <span class="tok-o">=</span>
<span class="tok-n">system</span><span class="tok-p">.</span><span class="tok-n">dealloc</span><span class="tok-p">(</span><span class="tok-n">data</span><span class="tok-p">)</span>
<span class="tok-k">proc </span><span class="tok-nf">getBigSurface</span><span class="tok-p">():</span> <span class="tok-n">Surface</span> <span class="tok-o">=</span>
<span class="tok-k">let</span> <span class="tok-n">f</span><span class="tok-p">:</span> <span class="tok-n">File</span> <span class="tok-o">=</span> <span class="tok-n">open</span><span class="tok-p">(</span><span class="tok-s">"big_surface.s"</span><span class="tok-p">,</span> <span class="tok-n">fmRead</span><span class="tok-p">)</span>
<span class="tok-c"># setFilePos(f, 0)</span>
<span class="tok-c"># https://www.cairographics.org/manual/cairo-Image-Surfaces.html#cairo-format-stride-for-width</span>
<span class="tok-k">let</span> <span class="tok-n">stride</span> <span class="tok-o">=</span> <span class="tok-n">cairo_format_stride_for_width</span><span class="tok-p">(</span><span class="tok-n">CFormat</span><span class="tok-p">,</span> <span class="tok-n">Width</span><span class="tok-p">)</span>
<span class="tok-n">bigSurfaceData</span> <span class="tok-o">=</span> <span class="tok-k">cast</span><span class="tok-o">[</span><span class="tok-k">ptr</span> <span class="tok-n">cuchar</span><span class="tok-o">]</span><span class="tok-p">(</span><span class="tok-n">malloc</span><span class="tok-p">((</span><span class="tok-n">stride</span> <span class="tok-o">*</span> <span class="tok-n">Height</span><span class="tok-p">).</span><span class="tok-n">uint64</span><span class="tok-p">))</span>
<span class="tok-kd">var</span> <span class="tok-n">len</span> <span class="tok-o">=</span> <span class="tok-n">readBuffer</span><span class="tok-p">(</span><span class="tok-n">f</span><span class="tok-p">,</span> <span class="tok-n">bigSurfaceData</span><span class="tok-p">,</span> <span class="tok-n">stride</span> <span class="tok-o">*</span> <span class="tok-n">Height</span><span class="tok-p">)</span>
<span class="tok-n">echo</span><span class="tok-p">(</span><span class="tok-s">"read </span><span class="tok-si">$1</span><span class="tok-s">"</span> <span class="tok-o">%</span> <span class="tok-o">$</span><span class="tok-n">len</span><span class="tok-p">)</span>
<span class="tok-n">close</span><span class="tok-p">(</span><span class="tok-n">f</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">bigSurface</span><span class="tok-p">:</span> <span class="tok-n">Surface</span> <span class="tok-o">=</span> <span class="tok-n">new</span> <span class="tok-n">Surface</span> <span class="tok-c"># this is a temporary fix, we will support this later in cairo modul</span>
<span class="tok-n">bigSurface</span><span class="tok-p">.</span><span class="tok-n">impl</span> <span class="tok-o">=</span> <span class="tok-n">cairo_image_surface_create_for_data</span><span class="tok-p">(</span><span class="tok-n">bigSurfaceData</span><span class="tok-p">,</span> <span class="tok-n">CFormat</span><span class="tok-p">,</span> <span class="tok-n">Width</span><span class="tok-p">,</span> <span class="tok-n">Height</span><span class="tok-p">,</span> <span class="tok-n">stride</span><span class="tok-p">)</span>
<span class="tok-k">discard</span> <span class="tok-n">setUserData</span><span class="tok-p">(</span><span class="tok-n">bigSurface</span><span class="tok-p">,</span> <span class="tok-k">addr</span><span class="tok-p">(</span><span class="tok-n">Key</span><span class="tok-p">),</span> <span class="tok-n">bigSurfaceData</span><span class="tok-p">,</span> <span class="tok-n">myDealloc</span><span class="tok-p">)</span> <span class="tok-c"># automatic deallocation</span>
<span class="tok-c"># flush(bigSurface)</span>
<span class="tok-n">echo</span><span class="tok-p">(</span><span class="tok-s">"open </span><span class="tok-si">$1</span><span class="tok-s">"</span> <span class="tok-o">%</span> <span class="tok-n">bigSurface</span><span class="tok-p">.</span><span class="tok-n">status</span><span class="tok-p">.</span><span class="tok-n">statusToString</span><span class="tok-p">)</span>
<span class="tok-k">return</span> <span class="tok-n">bigSurface</span>
<span class="tok-k">proc </span><span class="tok-nf">daDrawing</span><span class="tok-o">*</span><span class="tok-p">(</span><span class="tok-n">da</span><span class="tok-p">:</span> <span class="tok-n">DrawingArea</span><span class="tok-p">;</span> <span class="tok-n">cr</span><span class="tok-p">:</span> <span class="tok-n">Context</span><span class="tok-p">;</span> <span class="tok-n">bigSurface</span><span class="tok-p">:</span> <span class="tok-n">Surface</span><span class="tok-p">):</span> <span class="tok-kt">bool</span> <span class="tok-o">=</span>
<span class="tok-kd">var</span>
<span class="tok-n">width</span> <span class="tok-o">=</span> <span class="tok-n">da</span><span class="tok-p">.</span><span class="tok-n">getAllocatedWidth</span><span class="tok-p">.</span><span class="tok-kt">float</span>
<span class="tok-n">height</span> <span class="tok-o">=</span> <span class="tok-n">da</span><span class="tok-p">.</span><span class="tok-n">getAllocatedHeight</span><span class="tok-p">.</span><span class="tok-kt">float</span>
<span class="tok-n">originX</span> <span class="tok-o">=</span> <span class="tok-n">translateX</span>
<span class="tok-n">originY</span> <span class="tok-o">=</span> <span class="tok-n">translateY</span>
<span class="tok-sd">## Some constraints.</span>
<span class="tok-k">if</span> <span class="tok-n">translateX</span> <span class="tok-o">></span> <span class="tok-mf">5000.0</span> <span class="tok-o">-</span> <span class="tok-n">width</span><span class="tok-p">:</span>
<span class="tok-n">originX</span> <span class="tok-o">=</span> <span class="tok-mf">5000.0</span> <span class="tok-o">-</span> <span class="tok-n">width</span> <span class="tok-o">/</span> <span class="tok-n">scale</span>
<span class="tok-k">if</span> <span class="tok-n">translateY</span> <span class="tok-o">></span> <span class="tok-mf">5000.0</span> <span class="tok-o">-</span> <span class="tok-n">height</span><span class="tok-p">:</span>
<span class="tok-n">originY</span> <span class="tok-o">=</span> <span class="tok-mf">5000.0</span> <span class="tok-o">-</span> <span class="tok-n">height</span> <span class="tok-o">/</span> <span class="tok-n">scale</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">setSource</span><span class="tok-p">(</span><span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">)</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">paint</span>
<span class="tok-sd">## Partition the big surface.</span>
<span class="tok-kd">var</span> <span class="tok-n">littleSurface</span><span class="tok-p">:</span> <span class="tok-n">Surface</span> <span class="tok-o">=</span> <span class="tok-n">cairo</span><span class="tok-p">.</span><span class="tok-n">surfaceCreateForRectangle</span><span class="tok-p">(</span><span class="tok-n">bigSurface</span><span class="tok-p">,</span>
<span class="tok-n">originX</span><span class="tok-p">,</span> <span class="tok-n">originY</span><span class="tok-p">,</span> <span class="tok-n">width</span> <span class="tok-o">/</span> <span class="tok-n">scale</span><span class="tok-p">,</span> <span class="tok-n">height</span> <span class="tok-o">/</span> <span class="tok-n">scale</span><span class="tok-p">)</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">scale</span><span class="tok-p">(</span><span class="tok-n">scale</span><span class="tok-p">,</span> <span class="tok-n">scale</span><span class="tok-p">)</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">setSourceSurface</span><span class="tok-p">(</span><span class="tok-n">littleSurface</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">)</span>
<span class="tok-n">setFilter</span><span class="tok-p">(</span><span class="tok-n">getSource</span><span class="tok-p">(</span><span class="tok-n">cr</span><span class="tok-p">),</span> <span class="tok-n">cairo</span><span class="tok-p">.</span><span class="tok-n">Filter</span><span class="tok-p">.</span><span class="tok-n">bilinear</span><span class="tok-p">)</span>
<span class="tok-n">cr</span><span class="tok-p">.</span><span class="tok-n">paint</span>
<span class="tok-k">return</span> <span class="tok-kp">true</span>
<span class="tok-k">proc </span><span class="tok-nf">bye</span><span class="tok-p">(</span><span class="tok-n">w</span><span class="tok-p">:</span> <span class="tok-n">Window</span><span class="tok-p">)</span> <span class="tok-o">=</span>
<span class="tok-n">mainQuit</span><span class="tok-p">()</span>
<span class="tok-n">echo</span> <span class="tok-s">"Bye..."</span>
<span class="tok-k">proc </span><span class="tok-nf">main</span> <span class="tok-o">=</span>
<span class="tok-n">gtk</span><span class="tok-p">.</span><span class="tok-n">init</span><span class="tok-p">()</span>
<span class="tok-k">let</span> <span class="tok-n">window</span> <span class="tok-o">=</span> <span class="tok-n">newWindow</span><span class="tok-p">()</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">setTitle</span><span class="tok-p">(</span><span class="tok-s">"Big Surface2"</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">setDefaultSize</span><span class="tok-p">(</span><span class="tok-mi">500</span><span class="tok-p">,</span> <span class="tok-mi">500</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">setPosition</span><span class="tok-p">(</span><span class="tok-n">gtk</span><span class="tok-p">.</span><span class="tok-n">WindowPosition</span><span class="tok-p">.</span><span class="tok-n">center</span><span class="tok-p">)</span>
<span class="tok-n">window</span><span class="tok-p">.</span><span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-s">"destroy"</span><span class="tok-p">,</span> <span class="tok-n">bye</span><span class="tok-p">)</span>
<span class="tok-sd">## Get a test surface.</span>
<span class="tok-n">saveBigSurface</span><span class="tok-p">()</span>
<span class="tok-k">let</span> <span class="tok-n">bigSurface</span> <span class="tok-o">=</span> <span class="tok-n">getBigSurface</span><span class="tok-p">()</span>
<span class="tok-k">let</span> <span class="tok-n">da</span><span class="tok-p">:</span> <span class="tok-n">DrawingArea</span> <span class="tok-o">=</span> <span class="tok-n">newDrawingArea</span><span class="tok-p">()</span>
<span class="tok-n">da</span><span class="tok-p">.</span><span class="tok-n">setHexpand</span>
<span class="tok-n">da</span><span class="tok-p">.</span><span class="tok-n">setVexpand</span>
<span class="tok-n">da</span><span class="tok-p">.</span><span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-s">"draw"</span><span class="tok-p">,</span> <span class="tok-n">daDrawing</span><span class="tok-p">,</span> <span class="tok-n">bigSurface</span><span class="tok-p">)</span>
<span class="tok-k">let</span>
<span class="tok-n">translateXAdj</span> <span class="tok-o">=</span> <span class="tok-n">newAdjustment</span><span class="tok-p">(</span><span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">5000</span><span class="tok-p">,</span> <span class="tok-mi">20</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">)</span>
<span class="tok-n">translateYAdj</span> <span class="tok-o">=</span> <span class="tok-n">newAdjustment</span><span class="tok-p">(</span><span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">5000</span><span class="tok-p">,</span> <span class="tok-mi">20</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">)</span>
<span class="tok-n">scaleAdj</span> <span class="tok-o">=</span> <span class="tok-n">newAdjustment</span><span class="tok-p">(</span><span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">5</span><span class="tok-p">,</span> <span class="tok-mf">0.1</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">)</span>
<span class="tok-n">translateXLabel</span> <span class="tok-o">=</span> <span class="tok-n">newLabel</span><span class="tok-p">(</span><span class="tok-s">"translate x"</span><span class="tok-p">)</span>
<span class="tok-n">translateXSpin</span><span class="tok-o">=</span> <span class="tok-n">newSpinButton</span><span class="tok-p">(</span><span class="tok-n">translateXAdj</span><span class="tok-p">,</span> <span class="tok-mi">50</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">translateXSpin</span><span class="tok-p">,</span> <span class="tok-s">"value-changed"</span><span class="tok-p">,</span> <span class="tok-n">translateXSpinChanged</span><span class="tok-p">,</span> <span class="tok-n">da</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">translateYLabel</span> <span class="tok-o">=</span> <span class="tok-n">newLabel</span><span class="tok-p">(</span><span class="tok-s">"translate y"</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">translateYSpin</span> <span class="tok-o">=</span> <span class="tok-n">newSpinButton</span><span class="tok-p">(</span><span class="tok-n">translateYAdj</span><span class="tok-p">,</span> <span class="tok-mi">50</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">translateYSpin</span><span class="tok-p">,</span> <span class="tok-s">"value-changed"</span><span class="tok-p">,</span> <span class="tok-n">translateYSpinChanged</span><span class="tok-p">,</span> <span class="tok-n">da</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">scaleLabel</span> <span class="tok-o">=</span> <span class="tok-n">newLabel</span><span class="tok-p">(</span><span class="tok-s">"Scale"</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">scaleSpin</span> <span class="tok-o">=</span> <span class="tok-n">newSpinButton</span><span class="tok-p">(</span><span class="tok-n">scaleAdj</span><span class="tok-p">,</span> <span class="tok-mf">0.2</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">)</span>
<span class="tok-n">connect</span><span class="tok-p">(</span><span class="tok-n">scaleSpin</span><span class="tok-p">,</span> <span class="tok-s">"value-changed"</span><span class="tok-p">,</span> <span class="tok-n">scaleSpinChanged</span><span class="tok-p">,</span> <span class="tok-n">da</span><span class="tok-p">)</span>
<span class="tok-k">let</span> <span class="tok-n">grid</span> <span class="tok-o">=</span> <span class="tok-n">newGrid</span><span class="tok-p">()</span>
<span class="tok-n">grid</span><span class="tok-p">.</span><span class="tok-n">attach</span><span class="tok-p">(</span><span class="tok-n">da</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">3</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">)</span>
<span class="tok-n">grid</span><span class="tok-p">.</span><span class="tok-n">attach</span><span class="tok-p">(</span><span class="tok-n">translateXLabel</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">)</span>
<span class="tok-n">grid</span><span class="tok-p">.</span><span class="tok-n">attach</span><span class="tok-p">(</span><span class="tok-n">translateYLabel</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">)</span>
<span class="tok-n">grid</span><span class="tok-p">.</span><span class="tok-n">attach</span><span class="tok-p">(</span><span class="tok-n">scaleLabel</span><span class="tok-p">,</span> <span class="tok-mi">2</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">)</span>
<span class="tok-n">grid</span><span class="tok-p">.</span><span class="tok-n">attach</span><span class="tok-p">(</span><span class="tok-n">translateXSpin</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">2</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">)</span>
<span class="tok-n">grid</span><span class="tok-p">.</span><span class="tok-n">attach</span><span class="tok-p">(</span><span class="tok-n">translateYSpin</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">2</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">)</span>
<span class="tok-n">grid</span><span class="tok-p">.</span><span class="tok-n">attach</span><span class="tok-p">(</span><span class="tok-n">scaleSpin</span><span class="tok-p">,</span> <span class="tok-mi">2</span><span class="tok-p">,</span> <span class="tok-mi">2</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">)</span>
<span class="tok-n">add</span><span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">,</span> <span class="tok-n">grid</span><span class="tok-p">)</span>
<span class="tok-n">showAll</span><span class="tok-p">(</span><span class="tok-n">window</span><span class="tok-p">)</span>
<span class="tok-n">gtk</span><span class="tok-p">.</span><span class="tok-n">main</span><span class="tok-p">()</span>
<span class="tok-n">main</span><span class="tok-p">()</span></code></pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Related work: <a href="https://github.com/jdmansour/nim-smartgi" class="bare">https://github.com/jdmansour/nim-smartgi</a>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2019-09-15 18:26:13 +0200
</div>
</div>
</body>
</html>