https://agateau.com/tags/release-month/feedPosts tagged release-month2018-12-30T11:23:01+01:00Aurélien Gâteaupython-feedgenhttps://agateau.com/2018/doxyqml-0-5-0Release month, Doxyqml 0.5.02018-12-01T17:50:20+01:00<p>December just started, and this year I want to try to do something a bit similar to advent calendars: make a new release of one of my (too) many projects every weekend! This release month begins with the release of <a href="https://agateau.com/projects/doxyqml">Doxyqml</a> 0.5.0, an input filter to let you document your QML code using Doxygen.</p>
<!-- break -->
<p>Just like in <a href="https://agateau.com/2018/doxyqml-0-4-0">version 0.4.0</a>, most of the work has been done by other contributors, with me taking care of reviewing the code and improving project infrastructure (improving tests, adding coding style checks...). Here is the list of changes:</p>
<ul>
<li>Turn internal QML elements into private C++ members, see <a href="https://github.com/agateau/doxyqml">README.md</a> for details on how to use this. (Matthew Lam)</li>
<li>Add support for <code>@returns</code>, a synonym for <code>@return</code>. (Max Paperno)</li>
<li>Add support for trailing (inline) Doxygen comments for properties, signals, and methods (but not method parameters). (Max Paperno)</li>
<li>Fix installation issues on Windows (Max Paperno)</li>
<li>Improve test coverage and infrastructure (Aurélien Gâteau)</li>
<li>Setup flake8 to enforce coding style (Aurélien Gâteau)</li>
</ul>
<p>As usual, you can get it using pip:</p>
<div class="codehilite"><pre><span/><code>pip3 install --upgrade doxyqml
</code></pre></div>
<p>Or download the <a href="https://github.com/agateau/doxyqml">source code</a>.</p>
<p>That's it for this release, see you next weekend for a new release of another project...</p>2018-12-01T17:50:20+01:00https://agateau.com/2018/qpropgen-0-1-1Release month, qpropgen 0.1.12018-12-09T11:22:19+01:00<p>Continuing on this release month idea started <a href="https://agateau.com/2018/doxyqml-0-5-0">last week</a>, here is a release
of another project. Today is the first release of <a href="https://github.com/agateau/qpropgen">qpropgen</a>, a tool to generate
QML-friendly QObject-based C++ classes from class definition files.</p>
<!-- break -->
<p>I started this project because I did not want to manually define the dozen of
properties required to represent a sound in <a href="https://github.com/agateau/sfxr-qt">SFXR-Qt</a>, which itself got
started because I wanted a sound effect generator for <a href="https://agateau.com/projects/pixelwheels">Pixel Wheels</a>.
Yes, that's a bit of Yak shaving :)</p>
<p>It works this way: first you define your class and its properties in a yaml file:</p>
<div class="codehilite"><pre><span/><code><span class="nt">class</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">Person</span>
<span class="nt">properties</span><span class="p">:</span>
<span class="p p-Indicator">-</span> <span class="nt">name</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">firstName</span>
<span class="nt">type</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">QString</span>
<span class="p p-Indicator">-</span> <span class="nt">name</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">lastName</span>
<span class="nt">type</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">QString</span>
<span class="p p-Indicator">-</span> <span class="nt">name</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">birthDate</span>
<span class="nt">type</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">QDateTime</span>
</code></pre></div>
<p>Then you run <code>qpropgen person.yaml</code>. It produces two files: <code>person.h</code> and <code>person.cpp</code>.</p>
<p>This is <code>person.h</code>:</p>
<div class="codehilite"><pre><span/><code><span class="c1">// This file has been generated with qpropgen, any changes made to it will be lost!</span>
<span class="cp">#ifndef PERSON_H</span>
<span class="cp">#define PERSON_H</span>
<span class="cp">#include</span> <span class="cpf"><QObject></span><span class="cp"/>
<span class="k">class</span> <span class="nc">Person</span> <span class="o">:</span> <span class="k">public</span> <span class="n">QObject</span> <span class="p">{</span>
<span class="n">Q_OBJECT</span>
<span class="n">Q_PROPERTY</span><span class="p">(</span><span class="n">QString</span> <span class="n">firstName</span> <span class="n">READ</span> <span class="n">firstName</span>
<span class="n">WRITE</span> <span class="n">setFirstName</span>
<span class="n">NOTIFY</span> <span class="n">firstNameChanged</span>
<span class="p">)</span>
<span class="n">Q_PROPERTY</span><span class="p">(</span><span class="n">QString</span> <span class="n">lastName</span> <span class="n">READ</span> <span class="n">lastName</span>
<span class="n">WRITE</span> <span class="n">setLastName</span>
<span class="n">NOTIFY</span> <span class="n">lastNameChanged</span>
<span class="p">)</span>
<span class="n">Q_PROPERTY</span><span class="p">(</span><span class="n">QDateTime</span> <span class="n">birthDate</span> <span class="n">READ</span> <span class="n">birthDate</span>
<span class="n">WRITE</span> <span class="n">setBirthDate</span>
<span class="n">NOTIFY</span> <span class="n">birthDateChanged</span>
<span class="p">)</span>
<span class="k">public</span><span class="o">:</span>
<span class="k">explicit</span> <span class="n">Person</span><span class="p">(</span><span class="n">QObject</span><span class="o">*</span> <span class="n">parent</span> <span class="o">=</span> <span class="k">nullptr</span><span class="p">);</span>
<span class="n">QString</span> <span class="nf">firstName</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="kt">void</span> <span class="nf">setFirstName</span><span class="p">(</span><span class="k">const</span> <span class="n">QString</span><span class="o">&</span> <span class="n">value</span><span class="p">);</span>
<span class="n">QString</span> <span class="nf">lastName</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="kt">void</span> <span class="nf">setLastName</span><span class="p">(</span><span class="k">const</span> <span class="n">QString</span><span class="o">&</span> <span class="n">value</span><span class="p">);</span>
<span class="n">QDateTime</span> <span class="nf">birthDate</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="kt">void</span> <span class="nf">setBirthDate</span><span class="p">(</span><span class="k">const</span> <span class="n">QDateTime</span><span class="o">&</span> <span class="n">value</span><span class="p">);</span>
<span class="nl">signals</span><span class="p">:</span>
<span class="kt">void</span> <span class="n">firstNameChanged</span><span class="p">(</span><span class="k">const</span> <span class="n">QString</span><span class="o">&</span> <span class="n">firstName</span><span class="p">);</span>
<span class="kt">void</span> <span class="nf">lastNameChanged</span><span class="p">(</span><span class="k">const</span> <span class="n">QString</span><span class="o">&</span> <span class="n">lastName</span><span class="p">);</span>
<span class="kt">void</span> <span class="nf">birthDateChanged</span><span class="p">(</span><span class="k">const</span> <span class="n">QDateTime</span><span class="o">&</span> <span class="n">birthDate</span><span class="p">);</span>
<span class="k">private</span><span class="o">:</span>
<span class="n">QString</span> <span class="n">mFirstName</span><span class="p">;</span>
<span class="n">QString</span> <span class="n">mLastName</span><span class="p">;</span>
<span class="n">QDateTime</span> <span class="n">mBirthDate</span><span class="p">;</span>
<span class="p">};</span>
<span class="cp">#endif </span><span class="c1">// PERSON_H</span>
</code></pre></div>
<p>And this is <code>person.cpp</code>:</p>
<div class="codehilite"><pre><span/><code><span class="c1">// This file has been generated with qpropgen, any changes made to it will be lost!</span>
<span class="cp">#include</span> <span class="cpf"><person.h></span><span class="cp"/>
<span class="n">Person</span><span class="o">::</span><span class="n">Person</span><span class="p">(</span><span class="n">QObject</span><span class="o">*</span> <span class="n">parent</span><span class="p">)</span>
<span class="o">:</span> <span class="n">QObject</span><span class="p">(</span><span class="n">parent</span><span class="p">)</span> <span class="p">{</span>
<span class="p">}</span>
<span class="n">QString</span> <span class="n">Person</span><span class="o">::</span><span class="n">firstName</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">mFirstName</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">Person</span><span class="o">::</span><span class="n">setFirstName</span><span class="p">(</span><span class="k">const</span> <span class="n">QString</span><span class="o">&</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">mFirstName</span> <span class="o">==</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">mFirstName</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span>
<span class="n">firstNameChanged</span><span class="p">(</span><span class="n">value</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">QString</span> <span class="n">Person</span><span class="o">::</span><span class="n">lastName</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">mLastName</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">Person</span><span class="o">::</span><span class="n">setLastName</span><span class="p">(</span><span class="k">const</span> <span class="n">QString</span><span class="o">&</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">mLastName</span> <span class="o">==</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">mLastName</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span>
<span class="n">lastNameChanged</span><span class="p">(</span><span class="n">value</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">QDateTime</span> <span class="n">Person</span><span class="o">::</span><span class="n">birthDate</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">mBirthDate</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">Person</span><span class="o">::</span><span class="n">setBirthDate</span><span class="p">(</span><span class="k">const</span> <span class="n">QDateTime</span><span class="o">&</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">mBirthDate</span> <span class="o">==</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">mBirthDate</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span>
<span class="n">birthDateChanged</span><span class="p">(</span><span class="n">value</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>
<p>qpropgen comes with a CMake file to include in your project. Contributions adding support for other build systems are greatly appreciated :)</p>
<p>There is more to it: you can define read-only properties, make setters and getters virtual and a few other tweaks. You can learn more about qpropgen from the <a href="https://github.com/agateau/qpropgen">README</a>.</p>
<p>Let me know if you find this tool useful!</p>2018-12-09T11:22:19+01:00https://agateau.com/2018/pixelwheels-0-11-0Release month, Pixel Wheels 0.11.02018-12-16T20:30:24+01:00<p>Here is another release for the release month! This time it's a new release of
<a href="https://agateau.com/projects/pixelwheels">Pixel Wheels</a>. This one has been a long time coming: version 0.10.0 got
released in September.</p>
<!-- break -->
<p>So, what's new in this release? These changes:</p>
<ul>
<li>
<p>Pixel Wheels now remembers the best lap and best total time for each track
and shows you a congratulation message when you reach the top 3 in either
categories (This one is for you, Benjamin!)</p>
</li>
<li>
<p>Sounds have been added to the start up countdown.</p>
</li>
<li>
<p>The faster the vehicle is driving the more zoomed out the view is, giving you
more time to anticipate the track.</p>
</li>
<li>
<p>The game now shows a blocking message if there aren't enough gamepads to
start a game, or if a gamepad is disconnected while playing.</p>
</li>
<li>
<p>The focus indicator in the game menu has been reimplemented: now each menu
item has its own, fading, focus indicator. This fixes the focus indicator
glitches when a screen appeared or when switching between tabs in the
configuration screen.</p>
</li>
<li>
<p>The screens to select vehicles, tracks and championships now show the name of
the selected element. Furthermore, the track selection screen shows the
track records.</p>
</li>
<li>
<p>Fixed glitches when changing tabs in the configuration screen.</p>
</li>
<li>
<p>Added secret key shortcut to save a screenshot ('S' for now).</p>
</li>
<li>
<p>Switched desktop version to LWJGL3.</p>
</li>
<li>
<p>Updated libgdx to 1.9.8.</p>
</li>
<li>
<p>Make Google Play happy: bump <code>targetSdkVersion</code> to 26.</p>
</li>
</ul>
<p><img alt="Beat the best lap on Let it Snow!" src="https://agateau.com/2018/pixelwheels-0-11-0/best-lap.png"/></p>
<p>The addition of the best lap and total time records for each track took longer
than I expected, but I am happy with the end results: I think it improves the
game replay value.</p>2018-12-16T20:30:24+01:00https://agateau.com/2018/burgerparty-1-3-0Release month, Burger Party 1.3.0!2018-12-23T11:29:33+01:00<p>Another weekend, another release! This one is special. You may remember a few
years ago I created a burger game for Android: <a href="https://agateau.com/projects/burgerparty/">Burger Party</a>. At that time
I had plans to generate some revenue through this game. After investigating the
different revenue models, I sadly concluded <a href="https://agateau.com/2014/burgerparty-0.11/">I would have to include ads</a>.</p>
<p>That did not work out (surprise!): at its peak Burger Party reached a few
thousand installations, which generated a meager $30 of revenue. I guess the
reasons for this failure was that:</p>
<ol>
<li>There were not enough ads to make it work: I decided against permanent
banners so the game only displayed interstitials between levels, and no more
than one ad every two minutes,</li>
<li>It did not reach enough installations, marketing is not my forte.</li>
</ol>
<p>I also never felt comfortable with the idea of one my personal projects being
ad-based and proprietary. I kept telling myself I should remove the ads and
release a new version of Burger Party as free software, but I never got around
to do it...</p>
<p><img alt="Screenshot" src="https://agateau.com/projects/burgerparty/1.0rc1/us-world.png"/></p>
<!-- break -->
<p>Last week when I uploaded Pixel Wheels 0.11.0 to Google Play, I found out that
Burger Party had been pulled out because it did not have a privacy policy and
the ad SDK was sending data to the ad company. That decided me to finally take
the plunge and do the work.</p>
<p>Here it is: Burger Party, as of 1.3.0, is now ad-free and licensed under
GPL-3.0 or later, with some parts under Apache 2.0! And it's back on <a href="https://play.google.com/store/apps/details?id=com.agateau.burgerparty">Google
Play</a>!</p>
<p>You can find the complete game (source code and assets) on <a href="https://github.com/agateau/burgerparty">GitHub</a>.</p>
<h2>Music</h2>
<p>Speaking of assets, I am also happy to be able to share the game music,
which I like a lot:</p>
<p><audio controls="" style="width: 100%">
<source src="https://raw.githubusercontent.com/agateau/burgerparty/master/burgerparty-android/assets/music/burger-party_main-theme.mp3">
</source></audio></p>
<p>The music was composed by one of my brothers. It was not that easy for him to
produce, his band music is <a href="https://www.youtube.com/watch?v=ybRCS5xMQl8">slightly</a> <a href="https://www.youtube.com/watch?v=8tLvGizac8Y">more</a>
<a href="https://www.youtube.com/watch?v=p_4o_Z1QWCA">aggressive</a> :)</p>
<h2>Goodies</h2>
<p>To celebrate this release I created two T-shirts based on the game visuals:</p>
<div>
<a href="https://www.redbubble.com/people/agateau/works/35854931-burger?p=triblend-tee"><img style="width: 30%; display: inline" src="https://agateau.com/projects/burgerparty/tshirt-1.jpg"/></a>
<a href="https://www.redbubble.com/people/agateau/works/35854515-huge-burger?p=triblend-tee"><img style="width: 30%; display: inline" src="https://agateau.com/projects/burgerparty/tshirt-2.jpg"/></a>
</div>
<p>Who knows, maybe this can be more profitable than ads? It should not be too
difficult, considering I never got any money from the ad system because I never
reached the minimum threshold ($100) to actually get paid! In any case I prefer
earning a bit of money from someone buying a T-shirt than from someone clicking
on an ad and installing another app.</p>
<p>That's it for this release. I wish you a Merry Christmas! See you next weekend
for one last edition of the release month!</p>2018-12-23T11:29:33+01:00https://agateau.com/2018/nanonote-1-0-0Release month, Nanonote 1.0.02018-12-30T11:23:01+01:00<p>Here is the last issue of release month! Today is the first release of <a href="https://github.com/agateau/nanonote">Nanonote</a>, a minimalist note-taking application.</p>
<p><img alt="Screenshot" src="https://agateau.com/2018/nanonote-1-0-0/screenshot.png"/></p>
<p>Quoting the README:</p>
<blockquote>
<p>It automatically saves anything you type in the screen on your disk. Being minimalist means it has no synchronisation, does not support multiple documents, images or any advanced formatting (the only formatting is highlighting urls). If you have long-lived notes you should store them in a more permanent place.</p>
</blockquote>
<!-- break -->
<p>I built a very early version of Nanonote a little more than a year ago and since then I have been using it at work almost every day. I use it to take notes when I am investigating bugs or diving into a new code base, collecting links to pull requests and CI builds, whatever I need. It is basically an eco-friendly blank sheet.</p>
<p>The way I use it shaped some of the features like "Always on Top",
auto bullet-lists or the ability to indent and unindent text blocks with Ctrl+I and Ctrl+U (handy with nested lists).</p>
<p>Nanonote is built with Qt 5 and uses QWidgets, this might sound old-school, but it's lightweight, it works and QWidget <code>QPlainTextEdit</code> is superior to QtQuick Controls 2 <code>TextArea</code> at the moment, for example by providing a decent context menu.</p>
<p>There aren't any pre-compiled binaries for the moment, so you need to build it yourself. See the <a href="https://github.com/agateau/nanonote">README</a> for details.</p>
<p>That's the end of release month, I hope you enjoyed these releases!</p>2018-12-30T11:23:01+01:00