<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://thechange.wiki/index.php?action=history&amp;feed=atom&amp;title=Code%3Anodes.c</id>
	<title>Code:nodes.c - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://thechange.wiki/index.php?action=history&amp;feed=atom&amp;title=Code%3Anodes.c"/>
	<link rel="alternate" type="text/html" href="https://thechange.wiki/index.php?title=Code:nodes.c&amp;action=history"/>
	<updated>2026-04-27T20:46:10Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.41.0</generator>
	<entry>
		<id>https://thechange.wiki/index.php?title=Code:nodes.c&amp;diff=523&amp;oldid=prev</id>
		<title>Elie at 14:28, 30 November 2022</title>
		<link rel="alternate" type="text/html" href="https://thechange.wiki/index.php?title=Code:nodes.c&amp;diff=523&amp;oldid=prev"/>
		<updated>2022-11-30T14:28:57Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 10:28, 30 November 2022&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l1&quot;&gt;Line 1:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;Writing content sucks. Knowledge is complex and interconnected, but language is linear. No matter how much time you spend editing, it will never flow as well as it could.&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;That's why I decided to make a new format for content:&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;* Everything is a [[directed graph]].&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;* Nodes contain ''short'' pieces of text&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;** In the next versions, I plan to also have image nodes and [[calculator]] nodes.&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;* Think of it like a gigantic flowchart or mindmap, but you can fit more content than you ever could on a page.&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;I hope to turn this program into a web app, so that no one has to download &amp;amp; compile code just to view some content. For now, it's just a small experimental desktop app. It's very unfinished and I will probably change a lot in future versions. I haven't even written the usage instructions yet.&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;Author: [[User:Elie]]&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;==Dependencies==&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;Code&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;* [[Code:fullscreen_main.h]]&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;* [[Code:text-quads.h]]&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;Data&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;* [[File:font.data-uint8-1004x19]]&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;Installed programs&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;* [https://help.gnome.org/users/zenity/stable/ zenity]&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;* [http://tarot.freeshell.org/leafpad/ leafpad]&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;This program only runs on Linux.&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;==Code==&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;/***&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;/***&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>Elie</name></author>
	</entry>
	<entry>
		<id>https://thechange.wiki/index.php?title=Code:nodes.c&amp;diff=516&amp;oldid=prev</id>
		<title>Elie: Created page with &quot;&lt;syntaxhighlight lang=&quot;c&quot;&gt; /***  This is my new graph nodes program. I don't know what to call it yet.    To compile:     gcc nodes.c -o nodes -ffast-math -O -lm -lGL -lglut -lpthread   This program has runtime dependencies:     File in working directory: &quot;font.data-uint8-1004x19&quot;     Installed packages: 'zenity' and 'leafpad'   Copyright 2022, Elie Goldman Smith   This program is FREE SOFTWARE: you can redistribute it and/or modify  it under the terms of the GNU General...&quot;</title>
		<link rel="alternate" type="text/html" href="https://thechange.wiki/index.php?title=Code:nodes.c&amp;diff=516&amp;oldid=prev"/>
		<updated>2022-11-30T13:34:54Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt; /***  This is my new graph nodes program. I don&amp;#039;t know what to call it yet.    To compile:     gcc nodes.c -o nodes -ffast-math -O -lm -lGL -lglut -lpthread   This program has runtime dependencies:     File in working directory: &amp;quot;font.data-uint8-1004x19&amp;quot;     Installed packages: &amp;#039;zenity&amp;#039; and &amp;#039;leafpad&amp;#039;   Copyright 2022, Elie Goldman Smith   This program is FREE SOFTWARE: you can redistribute it and/or modify  it under the terms of the GNU General...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/***&lt;br /&gt;
 This is my new graph nodes program. I don't know what to call it yet.&lt;br /&gt;
 &lt;br /&gt;
 To compile:&lt;br /&gt;
    gcc nodes.c -o nodes -ffast-math -O -lm -lGL -lglut -lpthread&lt;br /&gt;
&lt;br /&gt;
 This program has runtime dependencies:&lt;br /&gt;
    File in working directory: &amp;quot;font.data-uint8-1004x19&amp;quot;&lt;br /&gt;
    Installed packages: 'zenity' and 'leafpad'&lt;br /&gt;
&lt;br /&gt;
 Copyright 2022, Elie Goldman Smith&lt;br /&gt;
&lt;br /&gt;
 This program is FREE SOFTWARE: you can redistribute it and/or modify&lt;br /&gt;
 it under the terms of the GNU General Public License as published by&lt;br /&gt;
 the Free Software Foundation, either version 3 of the License, or&lt;br /&gt;
 (at your option) any later version.&lt;br /&gt;
&lt;br /&gt;
 This program is distributed in the hope that it will be useful,&lt;br /&gt;
 but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
 GNU General Public License for more details.&lt;br /&gt;
&lt;br /&gt;
 You should have received a copy of the GNU General Public License&lt;br /&gt;
 along with this program.  If not, see &amp;lt;https://www.gnu.org/licenses/&amp;gt;.&lt;br /&gt;
***/&lt;br /&gt;
#include &amp;quot;fullscreen_main.h&amp;quot;&lt;br /&gt;
#include &amp;quot;text-quads.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;pthread.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define MAXTEXTLEVELS 7&lt;br /&gt;
const float TEXT_BOX_SIZES[MAXTEXTLEVELS] = {3, 4, 5, 7, 9, 11, 14}; // in 'em' units&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
 float x,y;&lt;br /&gt;
 float dx,dy;&lt;br /&gt;
 float size;&lt;br /&gt;
 unsigned char r,g,b,a;&lt;br /&gt;
 char *text;&lt;br /&gt;
 int nTextLevels;&lt;br /&gt;
 TQ_Drawable textRenders[MAXTEXTLEVELS];&lt;br /&gt;
} Node;&lt;br /&gt;
#define MAXNODES 4096&lt;br /&gt;
int nNodes=0;&lt;br /&gt;
Node nodes[MAXNODES];&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
 int from, to;&lt;br /&gt;
} Link;&lt;br /&gt;
#define MAXLINKS 4096&lt;br /&gt;
int nLinks=0;&lt;br /&gt;
Link links[MAXLINKS];&lt;br /&gt;
&lt;br /&gt;
int focus = 0; // index of node that is in focus (selected)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void addNodeFrom(int id) {&lt;br /&gt;
 if (nNodes &amp;gt;= MAXNODES) return;&lt;br /&gt;
 if (nLinks &amp;gt;= MAXLINKS) return;&lt;br /&gt;
 //focus=nNodes;&lt;br /&gt;
 nodes[nNodes].x = _mouse_x;&lt;br /&gt;
 nodes[nNodes].y = _mouse_y;&lt;br /&gt;
 nodes[nNodes].size = nodes[id].size + RND()*0.02f;&lt;br /&gt;
 int lum;&lt;br /&gt;
 lum = nodes[id].r + (rand()&amp;amp;255)-128; if(lum&amp;lt;0)lum=0; if(lum&amp;gt;255)lum=255; nodes[nNodes].r = lum;&lt;br /&gt;
 lum = nodes[id].g + (rand()&amp;amp;255)-128; if(lum&amp;lt;0)lum=0; if(lum&amp;gt;255)lum=255; nodes[nNodes].g = lum;&lt;br /&gt;
 lum = nodes[id].b + (rand()&amp;amp;255)-128; if(lum&amp;lt;0)lum=0; if(lum&amp;gt;255)lum=255; nodes[nNodes].b = lum;&lt;br /&gt;
 nodes[nNodes].a = 255;&lt;br /&gt;
 links[nLinks].from = id;&lt;br /&gt;
 links[nLinks].to   = nNodes;&lt;br /&gt;
 nLinks++;&lt;br /&gt;
 nNodes++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void toggleLink(int from, int to) {&lt;br /&gt;
 if (to==from) return;&lt;br /&gt;
 for (int i=0; i&amp;lt;nLinks; i++) {&lt;br /&gt;
  if (links[i].to==to &amp;amp;&amp;amp; links[i].from==from) { links[i] = links[--nLinks]; return; } // delete link   XXX: gotta update toMoveLink in some rare cases&lt;br /&gt;
  if (links[i].to==from &amp;amp;&amp;amp; links[i].from==to) { links[i].to=to; links[i].from=from; return; } // flip direction&lt;br /&gt;
 }&lt;br /&gt;
 if (nLinks &amp;gt;= MAXLINKS) return;&lt;br /&gt;
 links[nLinks].to   = to;&lt;br /&gt;
 links[nLinks].from = from;&lt;br /&gt;
 nLinks++;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int nodeNearest(float x, float y) {&lt;br /&gt;
 int which = 0;&lt;br /&gt;
 float lowest = 1e36;&lt;br /&gt;
 for (int i=0; i&amp;lt;nNodes; i++) {&lt;br /&gt;
  float dsq = (nodes[i].x - x)*(nodes[i].x - x) + (nodes[i].y - y)*(nodes[i].y - y);&lt;br /&gt;
  if (dsq &amp;lt; lowest) { lowest=dsq; which=i; }&lt;br /&gt;
 }&lt;br /&gt;
 return which;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void eraseNodeText(int id) {&lt;br /&gt;
 free(nodes[id].text);&lt;br /&gt;
 nodes[id].text = NULL;&lt;br /&gt;
 for (int tl=0; tl &amp;lt; nodes[id].nTextLevels; tl++) tq_delete(&amp;amp;nodes[id].textRenders[tl]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void deleteNode(int id) {&lt;br /&gt;
 eraseNodeText(id);&lt;br /&gt;
 nodes[id] = nodes[--nNodes];&lt;br /&gt;
 memset(&amp;amp;nodes[nNodes], 0, sizeof(Node));&lt;br /&gt;
 for (int i=0; i&amp;lt;nLinks; i++) {&lt;br /&gt;
  if (links[i].to==id || links[i].from==id) links[i--] = links[--nLinks];&lt;br /&gt;
  else {&lt;br /&gt;
   if (links[i].to == nNodes) links[i].to = id;&lt;br /&gt;
   if (links[i].from==nNodes) links[i].from=id;&lt;br /&gt;
  }&lt;br /&gt;
 } // XXX: also need to update references (toConnect, toPull, toMove, monitorEditNode, anything else?). If it's set to id, set to -1. If it's set to nNodes, set to id.&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void genNodeTextRenders(int id) {&lt;br /&gt;
 int tl=0;&lt;br /&gt;
 while (tl&amp;lt;MAXTEXTLEVELS) {&lt;br /&gt;
  nodes[id].textRenders[tl] = tq_centered_fitted(nodes[id].text, TEXT_BOX_SIZES[tl], TEXT_BOX_SIZES[tl]);&lt;br /&gt;
  if (nodes[id].textRenders[tl++].isComplete) break;&lt;br /&gt;
 }&lt;br /&gt;
 nodes[id].nTextLevels = tl;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void saveToFile(const char *filename) {&lt;br /&gt;
 FILE *f = fopen(filename,&amp;quot;w&amp;quot;);&lt;br /&gt;
 if (!f) return; // TODO: handle error case&lt;br /&gt;
 fprintf(f, &amp;quot;view:\nf=%d\nnodes:\n&amp;quot;, focus);&lt;br /&gt;
 for (int i=0; i&amp;lt;nNodes; i++) {&lt;br /&gt;
  fprintf(f, &amp;quot;i=%d c=%02X%02X%02X t=\&amp;quot;&amp;quot;, i, (int)nodes[i].r, (int)nodes[i].g, (int)nodes[i].b);&lt;br /&gt;
  char *p = nodes[i].text;&lt;br /&gt;
  if (p) {&lt;br /&gt;
   while (*p) {&lt;br /&gt;
    if     (*p=='\n') fputs(&amp;quot;\\n&amp;quot;, f);&lt;br /&gt;
    else if(*p=='\&amp;quot;') fputs(&amp;quot;\\\&amp;quot;&amp;quot;,f);&lt;br /&gt;
    else fputc(*p, f);&lt;br /&gt;
    p++;&lt;br /&gt;
   }&lt;br /&gt;
  }fprintf(f,&amp;quot;\&amp;quot;\n&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 fprintf(f,&amp;quot;connections:\n&amp;quot;);&lt;br /&gt;
 for (int i=0; i&amp;lt;nLinks; i++) fprintf(f, &amp;quot;a=%d b=%d\n&amp;quot;, links[i].from, links[i].to);&lt;br /&gt;
 fclose(f);&lt;br /&gt;
 printf(&amp;quot;Saved to file %s\n&amp;quot;, filename);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void loadFile(const char *filename) { // TODO: respond more robustly (i.e. to avoid segfault when trying to load an invalid file)&lt;br /&gt;
 int success = 0;&lt;br /&gt;
 FILE *f = fopen(filename, &amp;quot;r&amp;quot;);&lt;br /&gt;
 if (f) {&lt;br /&gt;
  if (fscanf(f,&amp;quot;view:\nf=%d\nnodes:\n&amp;quot;,&amp;amp;focus)&amp;gt;0) {&lt;br /&gt;
   // clear existing data&lt;br /&gt;
   for (int i=0; i&amp;lt;nNodes; i++) {&lt;br /&gt;
    eraseNodeText(i);&lt;br /&gt;
    nodes[i].x = RND();&lt;br /&gt;
    nodes[i].y = RND();&lt;br /&gt;
   }&lt;br /&gt;
   nNodes = nLinks = 0;&lt;br /&gt;
   // read nodes from file&lt;br /&gt;
   for (int i=0; i&amp;lt;MAXNODES; i++) {&lt;br /&gt;
    int id; int r,g,b; char c;&lt;br /&gt;
    if (fscanf(f, &amp;quot;i=%d c=%02X%02X%02X t=\&amp;quot;&amp;quot;, &amp;amp;id, &amp;amp;r, &amp;amp;g, &amp;amp;b)&amp;gt;0) {&lt;br /&gt;
     if (id &amp;gt;= 0 &amp;amp;&amp;amp; id &amp;lt; MAXNODES) {&lt;br /&gt;
      nodes[id].r=r; nodes[id].g=g; nodes[id].b=b; nodes[i].a=255;&lt;br /&gt;
      if (nNodes &amp;lt;= id) nNodes = id+1;&lt;br /&gt;
      size_t size;&lt;br /&gt;
      FILE *ss = open_memstream(&amp;amp;nodes[id].text, &amp;amp;size);&lt;br /&gt;
      while (1) {&lt;br /&gt;
       c = fgetc(f);&lt;br /&gt;
       if (c == '\&amp;quot;' || c == EOF) break;&lt;br /&gt;
       if (c == '\\') {&lt;br /&gt;
        c = fgetc(f);&lt;br /&gt;
        if      (c == EOF) break;&lt;br /&gt;
        if      (c == '\&amp;quot;') fputc('\&amp;quot;',ss);&lt;br /&gt;
        else if (c == 'n' ) fputc('\n',ss);&lt;br /&gt;
        else if (c == '\\') fputc('\\',ss);&lt;br /&gt;
        else {&lt;br /&gt;
         fputc('\\',ss);&lt;br /&gt;
         fputc(c, ss);&lt;br /&gt;
        }&lt;br /&gt;
       } else fputc(c, ss);&lt;br /&gt;
      } fclose(ss);&lt;br /&gt;
     }&lt;br /&gt;
    } else i=MAXNODES; // reached the line &amp;quot;connections:&amp;quot; so end this for-loop&lt;br /&gt;
    while ((c=fgetc(f)) != '\n' &amp;amp;&amp;amp; c != EOF); // skip to the next line&lt;br /&gt;
   }&lt;br /&gt;
   // read the list of connections from file&lt;br /&gt;
   for (int i=0; i&amp;lt;MAXLINKS; i++, nLinks++) {&lt;br /&gt;
    int a,b;&lt;br /&gt;
    if (fscanf(f,&amp;quot;a=%d b=%d\n&amp;quot;,&amp;amp;a,&amp;amp;b)==2) {&lt;br /&gt;
     links[i].from = a;&lt;br /&gt;
     links[i].to   = b;&lt;br /&gt;
    } else break;&lt;br /&gt;
   } success=1;&lt;br /&gt;
  }&lt;br /&gt;
  fclose(f);&lt;br /&gt;
  if (success) {&lt;br /&gt;
   for (int i=0; i&amp;lt;nNodes; i++) genNodeTextRenders(i); // this is done at the end because it might need a lot of memory (fclose() would have freed some)&lt;br /&gt;
   printf(&amp;quot;Opened file %s\n&amp;quot;, filename);&lt;br /&gt;
  } else printf(&amp;quot;Invalid file %s\n&amp;quot;, filename);&lt;br /&gt;
 } else perror(filename);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void drawCircle(float x, float y, float radius) {&lt;br /&gt;
 glBegin(GL_LINE_LOOP);&lt;br /&gt;
 float da=(float)M_PI/16.f;&lt;br /&gt;
 for (float a = da*0.5f; a &amp;lt; (float)M_PI*2.f; a += da) glVertex2f(x + cosf(a)*radius, y + sinf(a)*radius);&lt;br /&gt;
 glEnd();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
const    char *          monitorFileName = &amp;quot;/tmp/edit-text-node&amp;quot;;&lt;br /&gt;
volatile struct timespec monitorFileTime = {0};&lt;br /&gt;
volatile int             monitorEditNode = -1;&lt;br /&gt;
&lt;br /&gt;
void editTextNode(int id) {&lt;br /&gt;
 const char *editor_names[] = {&amp;quot;leafpad&amp;quot;,&amp;quot;defaulttexteditor&amp;quot;,&amp;quot;gedit&amp;quot;,&amp;quot;geany&amp;quot;,&amp;quot;notepad++&amp;quot;,&amp;quot;wordpad&amp;quot;,&amp;quot;notepad&amp;quot;,&amp;quot;nano&amp;quot;,&amp;quot;vim&amp;quot;,&amp;quot;vi&amp;quot;,&amp;quot;emacs&amp;quot;,NULL};&lt;br /&gt;
 FILE *f = fopen(monitorFileName, &amp;quot;w&amp;quot;);&lt;br /&gt;
 if (f) {&lt;br /&gt;
  if (nodes[id].text) fputs(nodes[id].text, f);&lt;br /&gt;
  fclose(f);&lt;br /&gt;
  struct stat st;&lt;br /&gt;
  stat(monitorFileName, &amp;amp;st);&lt;br /&gt;
  monitorFileTime = st.st_mtim;&lt;br /&gt;
  monitorEditNode = id;&lt;br /&gt;
  if (fork()==0) {&lt;br /&gt;
   for (int i=0; editor_names[i]; i++) execlp(editor_names[0], editor_names[0], monitorFileName, (char*)NULL);&lt;br /&gt;
   printf(&amp;quot;Can't edit node: No text editor found.\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
 else {} // TODO: handle error case&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void *fileMonitor(void *ptr) { // pthread&lt;br /&gt;
 while (1) {&lt;br /&gt;
  if (monitorEditNode &amp;gt;= 0) {&lt;br /&gt;
   struct stat st;&lt;br /&gt;
   stat(monitorFileName, &amp;amp;st);&lt;br /&gt;
   if (st.st_mtim.tv_sec != monitorFileTime.tv_sec || st.st_mtim.tv_nsec != monitorFileTime.tv_nsec) {&lt;br /&gt;
    char *str = malloc(st.st_size+1);&lt;br /&gt;
    if (!str) return NULL;        // TODO: handle error case&lt;br /&gt;
    FILE *f = fopen(monitorFileName, &amp;quot;r&amp;quot;);&lt;br /&gt;
    if(!f){free(str);return NULL;}// TODO: handle error case&lt;br /&gt;
    int n = fread(str, 1, st.st_size, f);&lt;br /&gt;
    str[n]=0;&lt;br /&gt;
    fclose(f);&lt;br /&gt;
    eraseNodeText(monitorEditNode);&lt;br /&gt;
    nodes[monitorEditNode].text = str;&lt;br /&gt;
    genNodeTextRenders(monitorEditNode);&lt;br /&gt;
    monitorFileTime = st.st_mtim;&lt;br /&gt;
    monitorEditNode = -1;&lt;br /&gt;
   }&lt;br /&gt;
  } sleep(1);&lt;br /&gt;
 }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void init() {&lt;br /&gt;
 tq_init(); glDisable(GL_TEXTURE_2D);&lt;br /&gt;
 show_mouse();&lt;br /&gt;
 memset(nodes, 0, sizeof(nodes)); // this also initializes any pointers to NULL, so it's safe to call free() on them at any time&lt;br /&gt;
 memset(links, -1,sizeof(links)); // -1 is safe, will be interpereted as 'not a link'&lt;br /&gt;
 if (_global_argc==2) loadFile(_global_argv[1]);&lt;br /&gt;
 if (nNodes &amp;lt; 1) {&lt;br /&gt;
  // root node&lt;br /&gt;
  nodes[nNodes].size = 0.04f;&lt;br /&gt;
  nodes[nNodes].r = 255;&lt;br /&gt;
  nodes[nNodes].g = 255;&lt;br /&gt;
  nodes[nNodes].b = 255;&lt;br /&gt;
  nodes[nNodes].a = 255;&lt;br /&gt;
  nNodes++;&lt;br /&gt;
 }&lt;br /&gt;
 pthread_t fm; // file monitor thread (for editing a node)&lt;br /&gt;
 pthread_create(&amp;amp;fm,NULL,fileMonitor,NULL);&lt;br /&gt;
 #ifdef USE_MULTISAMPLING&lt;br /&gt;
 glLineWidth(1.5f);&lt;br /&gt;
 #endif&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void draw() {&lt;br /&gt;
 //==User interface==&lt;br /&gt;
&lt;br /&gt;
 // select node (Left click)&lt;br /&gt;
 if (_mouse_button_map[0]==KEY_FRESHLY_PRESSED) focus = nodeNearest(_mouse_x, _mouse_y);&lt;br /&gt;
&lt;br /&gt;
 // drag node (Right click)&lt;br /&gt;
 static int toPull = -1;&lt;br /&gt;
 if (_mouse_button_map[2]==KEY_FRESHLY_PRESSED) toPull = nodeNearest(_mouse_x, _mouse_y);&lt;br /&gt;
 if (_mouse_button_map[2] &amp;amp;&amp;amp; toPull &amp;gt;= 0) { nodes[toPull].x = _mouse_x; nodes[toPull].y = _mouse_y; } else toPull = -1;&lt;br /&gt;
&lt;br /&gt;
 // new node (N)&lt;br /&gt;
 if (keymap['N']==KEY_FRESHLY_PRESSED) addNodeFrom(focus);&lt;br /&gt;
&lt;br /&gt;
 // edit node text (E)&lt;br /&gt;
 if (keymap['E']==KEY_FRESHLY_PRESSED) editTextNode(focus);&lt;br /&gt;
&lt;br /&gt;
 // connect nodes (C, and then Enter or Space)&lt;br /&gt;
 static int toConnect = -1;&lt;br /&gt;
 if (keymap['C']==KEY_FRESHLY_PRESSED) {&lt;br /&gt;
  if (toConnect &amp;lt; 0) toConnect = focus;&lt;br /&gt;
  else toConnect = -1;&lt;br /&gt;
 }&lt;br /&gt;
 if (toConnect &amp;gt;= 0) {&lt;br /&gt;
  if (keymap[13]==KEY_FRESHLY_PRESSED) { toggleLink(toConnect, focus); toConnect = -1; }&lt;br /&gt;
  if (keymap[' ']==KEY_FRESHLY_PRESSED){ toggleLink(focus, toConnect); toConnect = -1; }&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 // move node (M, and then Enter or Space)&lt;br /&gt;
 static int toMove = -1;&lt;br /&gt;
 static int toMoveLink = -1;&lt;br /&gt;
 if (keymap['M']==KEY_FRESHLY_PRESSED) {&lt;br /&gt;
  if (toMove != focus) {&lt;br /&gt;
   toMove = focus;&lt;br /&gt;
   toMoveLink = -1;&lt;br /&gt;
  }&lt;br /&gt;
  while (++toMoveLink &amp;lt; nLinks) { if (links[toMoveLink].to == toMove) break; }&lt;br /&gt;
  if (toMoveLink &amp;gt;= nLinks) toMoveLink = toMove = -1;&lt;br /&gt;
 }&lt;br /&gt;
 if (toMove &amp;gt;= 0 &amp;amp;&amp;amp; toMove != focus) {&lt;br /&gt;
  if (keymap[13]==KEY_FRESHLY_PRESSED) { links[toMoveLink].from=focus; toMoveLink=toMove=-1; }&lt;br /&gt;
  if (keymap[' ']==KEY_FRESHLY_PRESSED){ links[toMoveLink].from=toMove; links[toMoveLink].to=focus; toMoveLink=toMove=-1; }  &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 // delete node (Delete)&lt;br /&gt;
 if (keymap[127]==KEY_FRESHLY_PRESSED &amp;amp;&amp;amp; nNodes&amp;gt;1) { deleteNode(focus); focus = nodeNearest(0,0); }&lt;br /&gt;
&lt;br /&gt;
 // help (F1)&lt;br /&gt;
 if (special_keymap[GLUT_KEY_F1]==KEY_FRESHLY_PRESSED) {} // TODO: implement. First have to write the help info.&lt;br /&gt;
&lt;br /&gt;
 // back button (Backspace)&lt;br /&gt;
 if (keymap[8] == KEY_FRESHLY_PRESSED) {} // TODO: implement. Need stack and need to figure out what to do in case of deleted nodes&lt;br /&gt;
&lt;br /&gt;
 // save file (Ctrl-S or F5)&lt;br /&gt;
 if (keymap[19] ==KEY_FRESHLY_PRESSED || (special_keymap[114] &amp;amp;&amp;amp; keymap['S']==KEY_FRESHLY_PRESSED) || special_keymap[GLUT_KEY_F5]==KEY_FRESHLY_PRESSED) {&lt;br /&gt;
  char filename[4096];&lt;br /&gt;
  FILE *f = popen(&amp;quot;zenity --file --title 'Save as...' --save --confirm-overwrite 'Overwrite existing file?' --maximized --close-on-unfocus&amp;quot;, &amp;quot;r&amp;quot;);&lt;br /&gt;
  if (f) {&lt;br /&gt;
   char *c = fgets(filename,4096,f);&lt;br /&gt;
   if (pclose(f)==0) {&lt;br /&gt;
    int len=strlen(filename);&lt;br /&gt;
    if (len&amp;gt;1) {&lt;br /&gt;
     filename[len-1] = 0; // to remove the newline&lt;br /&gt;
     saveToFile(filename);&lt;br /&gt;
    } else puts(&amp;quot;Empty filename&amp;quot;);&lt;br /&gt;
   } else puts(&amp;quot;No filename selected&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
 // load file (Ctrl-O or F6)&lt;br /&gt;
 if (keymap[15] ==KEY_FRESHLY_PRESSED || (special_keymap[114] &amp;amp;&amp;amp; keymap['O']==KEY_FRESHLY_PRESSED) || special_keymap[GLUT_KEY_F6]==KEY_FRESHLY_PRESSED) {&lt;br /&gt;
  char filename[4096];&lt;br /&gt;
  FILE *f = popen(&amp;quot;zenity --file --title 'Open graph file...' --maximized --close-on-unfocus&amp;quot;, &amp;quot;r&amp;quot;); // or could also use --on-top&lt;br /&gt;
  if (f) {&lt;br /&gt;
   char *c = fgets(filename,4096,f);&lt;br /&gt;
   if (pclose(f)==0) {&lt;br /&gt;
    int len=strlen(filename);&lt;br /&gt;
    if (len&amp;gt;1) {&lt;br /&gt;
     filename[len-1] = 0; // to remove the newline&lt;br /&gt;
     loadFile(filename);&lt;br /&gt;
    } else puts(&amp;quot;Empty filename&amp;quot;);&lt;br /&gt;
   } else puts(&amp;quot;No filename selected&amp;quot;);&lt;br /&gt;
  } // XXX: need to decide: which messages should be in stdout vs stderr&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 //==Physics==&lt;br /&gt;
 // center the graph&lt;br /&gt;
 if (!_mouse_button_map[2]) {&lt;br /&gt;
  static float dx=0; dx *= 0.875f; dx += nodes[focus].x / -128;&lt;br /&gt;
  static float dy=0; dy *= 0.875f; dy += nodes[focus].y / -128;&lt;br /&gt;
  for (int i=0; i&amp;lt;nNodes; i++) {&lt;br /&gt;
   nodes[i].x += dx;&lt;br /&gt;
   nodes[i].y += dy;&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
 // establish which nodes are &amp;quot;relevant&amp;quot; aka potentially onscreen&lt;br /&gt;
 static Node* r[MAXNODES];&lt;br /&gt;
 int nRelevant=0;&lt;br /&gt;
 for (int i=0; i&amp;lt;nNodes; i++) {&lt;br /&gt;
  if (nodes[i].x*nodes[i].x + nodes[i].y*nodes[i].y &amp;lt; 4.f) {&lt;br /&gt;
   r[nRelevant++] = &amp;amp;nodes[i];&lt;br /&gt;
   nodes[i].size=0.5f;&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
 // apply bond forces&lt;br /&gt;
 for (int i=0; i&amp;lt;nLinks; i++) {&lt;br /&gt;
  float dx = nodes[links[i].to].x - nodes[links[i].from].x;&lt;br /&gt;
  float dy = nodes[links[i].to].y - nodes[links[i].from].y;&lt;br /&gt;
  float inv = 0.002f / sqrtf(dx*dx+dy*dy+1.f);&lt;br /&gt;
  dx *= inv; dy *= inv;      // dy += 0.0002f; // bias to make the graph flow in one direction slightly&lt;br /&gt;
  nodes[links[i].to  ].dx -= dx;&lt;br /&gt;
  nodes[links[i].to  ].dy -= dy;&lt;br /&gt;
  nodes[links[i].from].dx += dx;&lt;br /&gt;
  nodes[links[i].from].dy += dy;&lt;br /&gt;
 }&lt;br /&gt;
 // apply repel forces&lt;br /&gt;
 for (int h = 0; h&amp;lt;nRelevant; h++) {&lt;br /&gt;
  for (int i=h+1; i&amp;lt;nRelevant; i++) {&lt;br /&gt;
   float dx = r[i]-&amp;gt;x - r[h]-&amp;gt;x;&lt;br /&gt;
   float dy = r[i]-&amp;gt;y - r[h]-&amp;gt;y;&lt;br /&gt;
   float maxsize = fabs(dx) &amp;gt; fabs(dy) ? fabs(dx) : fabs(dy); maxsize *= 0.44f;&lt;br /&gt;
   if (r[h]-&amp;gt;size &amp;gt; maxsize) r[h]-&amp;gt;size = maxsize;&lt;br /&gt;
   if (r[i]-&amp;gt;size &amp;gt; maxsize) r[i]-&amp;gt;size = maxsize;&lt;br /&gt;
   if (maxsize &amp;lt; 0.0001f) { r[i]-&amp;gt;x += RND()*0.0001f; r[i]-&amp;gt;y += RND()*0.0001f; }&lt;br /&gt;
   float dsq = dx*dx+dy*dy;&lt;br /&gt;
   float inv = 1.f/sqrtf(dsq+0.01f); // for normalizing&lt;br /&gt;
   inv *= 0.00001f*inv*inv; // for inverse square law&lt;br /&gt;
   float falloff = 0.142857f*(7.f - r[i]-&amp;gt;x*r[i]-&amp;gt;x - r[i]-&amp;gt;y*r[i]-&amp;gt;y - r[h]-&amp;gt;x*r[h]-&amp;gt;x - r[h]-&amp;gt;y*r[h]-&amp;gt;y);&lt;br /&gt;
   if (falloff &amp;lt; 0.f) falloff = 0.f;&lt;br /&gt;
   inv *= falloff*falloff; // for clustering in distance&lt;br /&gt;
   dx *= inv; dy *= inv;&lt;br /&gt;
   r[h]-&amp;gt;dx -= dx;&lt;br /&gt;
   r[h]-&amp;gt;dy -= dy;&lt;br /&gt;
   r[i]-&amp;gt;dx += dx;&lt;br /&gt;
   r[i]-&amp;gt;dy += dy;&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
 // update positions&lt;br /&gt;
 for (int i=0; i&amp;lt;nNodes; i++) {&lt;br /&gt;
  nodes[i].x += nodes[i].dx;&lt;br /&gt;
  nodes[i].y += nodes[i].dy;&lt;br /&gt;
  nodes[i].dx *= 0.9375f;&lt;br /&gt;
  nodes[i].dy *= 0.9375f;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 //==Rendering==&lt;br /&gt;
 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);&lt;br /&gt;
&lt;br /&gt;
 // this projection matrix gives us &amp;quot;aspect-ratio-independent&amp;quot; normalized coordinates instead of the standard &amp;quot;normalized device coordinates&amp;quot;&lt;br /&gt;
 glMatrixMode(GL_PROJECTION);&lt;br /&gt;
 glLoadIdentity();&lt;br /&gt;
 glScalef((GLfloat)_screen_size/(GLfloat)_screen_x, (GLfloat)_screen_size/(GLfloat)_screen_y, 1.f);&lt;br /&gt;
&lt;br /&gt;
 // draw the links&lt;br /&gt;
 glBegin(GL_LINES);&lt;br /&gt;
 glColor3f(1.f,1.f,1.f);&lt;br /&gt;
 for (int i=0; i&amp;lt;nLinks; i++) {&lt;br /&gt;
  if (links[i].to &amp;gt;= 0 &amp;amp;&amp;amp; links[i].from &amp;gt;= 0) {&lt;br /&gt;
   // main line&lt;br /&gt;
   glVertex2f(nodes[links[i].to  ].x, nodes[links[i].to  ].y);&lt;br /&gt;
   glVertex2f(nodes[links[i].from].x, nodes[links[i].from].y);&lt;br /&gt;
   // add subtle chevron at the midpoint of the line, to indicate direction&lt;br /&gt;
   float mx =(nodes[links[i].to].x + nodes[links[i].from].x)*0.5f;&lt;br /&gt;
   float my =(nodes[links[i].to].y + nodes[links[i].from].y)*0.5f;&lt;br /&gt;
   float dx = nodes[links[i].to].x - nodes[links[i].from].x;&lt;br /&gt;
   float dy = nodes[links[i].to].y - nodes[links[i].from].y;&lt;br /&gt;
   float norm = 0.007f / sqrtf(dx*dx + dy*dy);&lt;br /&gt;
   dx *= norm;&lt;br /&gt;
   dy *= norm;&lt;br /&gt;
   glVertex2f(mx-dy-dx, my+dx-dy);&lt;br /&gt;
   glVertex2f(mx   +dx, my   +dy);&lt;br /&gt;
   glVertex2f(mx   +dx, my   +dy);&lt;br /&gt;
   glVertex2f(mx+dy-dx, my-dx-dy);&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
 glEnd();&lt;br /&gt;
&lt;br /&gt;
 // show new connection to be added (if there is one pending)&lt;br /&gt;
 if (toConnect &amp;gt;= 0) {&lt;br /&gt;
  glColor3f(0.7f,0.f,0.f);&lt;br /&gt;
  glBegin(GL_LINES);&lt;br /&gt;
  glVertex2f(nodes[toConnect].x, nodes[toConnect].y);&lt;br /&gt;
  glVertex2f(nodes[focus].x,     nodes[focus].y);&lt;br /&gt;
  glEnd();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 // show connection that may be moved (if there is one pending)&lt;br /&gt;
 if (toMoveLink &amp;gt;= 0) {&lt;br /&gt;
  glColor3f(0.0f,0.5f,0.5f);&lt;br /&gt;
  glBegin(GL_LINES);&lt;br /&gt;
  glVertex2f(nodes[links[toMoveLink].from].x, nodes[links[toMoveLink].from].y);&lt;br /&gt;
  glVertex2f(nodes[links[toMoveLink].to  ].x, nodes[links[toMoveLink].to  ].y);&lt;br /&gt;
  glEnd();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 // precalculate screen boundaries&lt;br /&gt;
 float bx = _screen_x / _screen_size;&lt;br /&gt;
 float by = _screen_y / _screen_size;&lt;br /&gt;
&lt;br /&gt;
 // draw the nodes&lt;br /&gt;
 for (int i=0; i&amp;lt;nRelevant; i++) { // this implementation uses Immediate Mode. XXX: instead of this, maybe use a vertex array with GL_POINTS, use point sprites with a shader that makes the rounded square shape?&lt;br /&gt;
  if (r[i]-&amp;gt;size &amp;gt; 0) {&lt;br /&gt;
   float x1 = r[i]-&amp;gt;x-r[i]-&amp;gt;size;&lt;br /&gt;
   float y1 = r[i]-&amp;gt;y-r[i]-&amp;gt;size;&lt;br /&gt;
   float x2 = r[i]-&amp;gt;x+r[i]-&amp;gt;size;&lt;br /&gt;
   float y2 = r[i]-&amp;gt;y+r[i]-&amp;gt;size;&lt;br /&gt;
   float c  = r[i]-&amp;gt;size*0.57f; if (c&amp;gt;0.01f) c=0.01f; // corner size&lt;br /&gt;
   if (x1&amp;lt;bx &amp;amp;&amp;amp; x2&amp;gt;-bx &amp;amp;&amp;amp; y1&amp;lt;by &amp;amp;&amp;amp; y2&amp;gt;-by) {&lt;br /&gt;
    glBegin(GL_POLYGON);&lt;br /&gt;
    glColor3ub(r[i]-&amp;gt;r, r[i]-&amp;gt;g, r[i]-&amp;gt;b);&lt;br /&gt;
    glVertex2f(x2-c, y2  );&lt;br /&gt;
    glVertex2f(x1+c, y2  );&lt;br /&gt;
    glVertex2f(x1  , y2-c);&lt;br /&gt;
    glVertex2f(x1  , y1+c);&lt;br /&gt;
    glVertex2f(x1+c, y1  );&lt;br /&gt;
    glVertex2f(x2-c, y1  );&lt;br /&gt;
    glVertex2f(x2  , y1+c);&lt;br /&gt;
    glVertex2f(x2  , y2-c);&lt;br /&gt;
    glEnd();&lt;br /&gt;
   }&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 // draw the text on the nodes&lt;br /&gt;
 glPushAttrib(GL_ENABLE_BIT); tq_mode();&lt;br /&gt;
 glColor3ub(255,255,255);&lt;br /&gt;
 for (int i=0; i&amp;lt;nRelevant; i++) {&lt;br /&gt;
  // filter out nodes with nothing to show&lt;br /&gt;
  if (r[i]-&amp;gt;textRenders[0].n &amp;lt;= 0) continue;&lt;br /&gt;
  if (r[i]-&amp;gt;x - r[i]-&amp;gt;size  &amp;gt;  bx) continue;&lt;br /&gt;
  if (r[i]-&amp;gt;x + r[i]-&amp;gt;size  &amp;lt; -bx) continue;&lt;br /&gt;
  if (r[i]-&amp;gt;y - r[i]-&amp;gt;size  &amp;gt;  by) continue;&lt;br /&gt;
  if (r[i]-&amp;gt;y + r[i]-&amp;gt;size  &amp;lt; -by) continue;&lt;br /&gt;
  // decide which textRender to use, if any.&lt;br /&gt;
  const float FONT_SIZE = 0.015f; // (nominal minimum)&lt;br /&gt;
  int tl = r[i]-&amp;gt;nTextLevels-1;&lt;br /&gt;
  while(tl &amp;gt;= 0 &amp;amp;&amp;amp; TEXT_BOX_SIZES[tl]*FONT_SIZE*0.5f &amp;gt; r[i]-&amp;gt;size) tl--;&lt;br /&gt;
  if   (tl &amp;gt;= 0) {&lt;br /&gt;
   // decide whether to make the text black or white&lt;br /&gt;
   if (0.2126f*r[i]-&amp;gt;r + 0.7152f*r[i]-&amp;gt;g + 0.0722f*r[i]-&amp;gt;b &amp;gt; 144) glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); else glBlendEquation(GL_FUNC_ADD);&lt;br /&gt;
   // render&lt;br /&gt;
   glPushMatrix();&lt;br /&gt;
   glTranslatef(r[i]-&amp;gt;x, r[i]-&amp;gt;y, 0.f);&lt;br /&gt;
   float scale = r[i]-&amp;gt;size * 2.f / TEXT_BOX_SIZES[tl];&lt;br /&gt;
   glScalef(scale, scale, 1.f);&lt;br /&gt;
   tq_draw(r[i]-&amp;gt;textRenders[tl]);&lt;br /&gt;
   tq_draw(r[i]-&amp;gt;textRenders[tl]); // TODO: instead of drawing twice, make a higher-contrast shader in text-quads.h&lt;br /&gt;
   glPopMatrix();&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
 glPopAttrib();&lt;br /&gt;
&lt;br /&gt;
 // highlight focused node&lt;br /&gt;
 glColor3f(1.f,1.f,0.f);&lt;br /&gt;
 drawCircle(nodes[focus].x, nodes[focus].y, nodes[focus].size*(float)M_SQRT2);&lt;br /&gt;
&lt;br /&gt;
 // highlight node to be connected&lt;br /&gt;
 glColor3f(1.f,0.f,0.f);&lt;br /&gt;
 drawCircle(nodes[toConnect].x, nodes[toConnect].y, nodes[toConnect].size*(float)M_SQRT2);&lt;br /&gt;
&lt;br /&gt;
 // highlight node being edited&lt;br /&gt;
 glColor3f(0.f,0.f,1.f);&lt;br /&gt;
 drawCircle(nodes[monitorEditNode].x, nodes[monitorEditNode].y, nodes[monitorEditNode].size*(float)M_SQRT2);&lt;br /&gt;
&lt;br /&gt;
 // highlight node to be moved&lt;br /&gt;
 glColor3f(0.0f,0.5f,0.5f);&lt;br /&gt;
 drawCircle(nodes[toMove].x, nodes[toMove].y, nodes[toMove].size*(float)M_SQRT2);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void done() {&lt;br /&gt;
 for (int i=0; i&amp;lt;nNodes; i++) eraseNodeText(i);&lt;br /&gt;
 tq_done();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Elie</name></author>
	</entry>
</feed>