<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>UI &#8211; Xojo Programming Blog</title>
	<atom:link href="https://blog.xojo.com/tag/ui/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.xojo.com</link>
	<description>Blog about the Xojo programming language and IDE</description>
	<lastBuildDate>Tue, 09 Dec 2025 16:31:54 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
	<item>
		<title>macOS and iOS: UI Compatibility Mode</title>
		<link>https://blog.xojo.com/2025/12/09/macos-and-ios-ui-compatibility-mode/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Tue, 09 Dec 2025 16:31:52 +0000</pubDate>
				<category><![CDATA[iOS]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[2025r3]]></category>
		<category><![CDATA[Liquid Glass]]></category>
		<category><![CDATA[macOS 26]]></category>
		<category><![CDATA[macOS Tahoe]]></category>
		<category><![CDATA[UI]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=15600</guid>

					<description><![CDATA[macOS 26 and iOS 26 bring many changes, most notably a major UI overhaul. This means that some elements in your existing layouts, both small&#8230;]]></description>
										<content:encoded><![CDATA[
<p>macOS 26 and iOS 26 bring many changes, most notably a major UI overhaul. This means that some elements in your existing layouts, both small and significant, may look different. To help developers with this transition, Apple has introduced UI Compatibility Mode in both operating systems for this release.</p>



<p>So, what is UI Compatibility Mode? It’s Apple’s way of ensuring that your app’s UI appears in macOS 26 and iOS 26 just as it did on previous OS versions. No Liquid Glass effects, no unexpected changes in control sizes or behavior, everything stays as you designed it. This means your pixel-perfect layouts from older OS versions, like Sequoia or iOS 18, will continue to look exactly as intended.</p>



<p>More technically, when UI Compatibility Mode is enabled, your app behaves as if it were compiled with an earlier SDK.</p>



<p>The caveat: Apple only guarantees this behavior while macOS 26 and iOS 26 are current. With the next major OS releases, this mode may no longer be available, so it’s a temporary solution.</p>



<p>The upside: At the time of writing, Apple is still refining these OS versions with point releases. If you need your app to run on macOS 26 or iOS 26 with full compatibility, you can enable UI Compatibility Mode in the Inspector Panel under Build Settings &gt; macOS and Build Settings &gt; iOS.</p>



<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="441" src="https://blog.xojo.com/wp-content/uploads/2025/12/CompatibilityModeSwitch-1024x441.png" alt="" class="wp-image-15606" srcset="https://blog.xojo.com/wp-content/uploads/2025/12/CompatibilityModeSwitch-1024x441.png 1024w, https://blog.xojo.com/wp-content/uploads/2025/12/CompatibilityModeSwitch-300x129.png 300w, https://blog.xojo.com/wp-content/uploads/2025/12/CompatibilityModeSwitch-768x331.png 768w, https://blog.xojo.com/wp-content/uploads/2025/12/CompatibilityModeSwitch.png 1234w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>When enabled, both your debugged apps and the built versions (including those submitted to Apple via Publish) will look and behave on macOS 26 and iOS 26 as if they were compiled with the previous SDK. In fact, the behavior is even more consistent than if they had been compiled using the prior Xojo release.</p>



<p>Below, you can see how the same app appears when running on macOS 26 and iOS 26 with UI Compatibility Mode turned off (showing Liquid Glass and all the new UI effects), compared to how it looks when the switch is turned on:</p>



<figure class="wp-block-image size-full"><img decoding="async" src="https://blog.xojo.com/wp-content/uploads/2025/12/UICompatibilityModeMacOS.png" alt="" class="wp-image-15601"/></figure>



<figure class="wp-block-image size-large"><img decoding="async" width="970" height="1024" src="https://blog.xojo.com/wp-content/uploads/2025/12/UICompatibilityModeiOS-970x1024.png" alt="" class="wp-image-15603" srcset="https://blog.xojo.com/wp-content/uploads/2025/12/UICompatibilityModeiOS-970x1024.png 970w, https://blog.xojo.com/wp-content/uploads/2025/12/UICompatibilityModeiOS-284x300.png 284w, https://blog.xojo.com/wp-content/uploads/2025/12/UICompatibilityModeiOS-768x811.png 768w, https://blog.xojo.com/wp-content/uploads/2025/12/UICompatibilityModeiOS.png 1697w" sizes="(max-width: 970px) 100vw, 970px" /></figure>



<h2 class="wp-block-heading">The Last Word</h2>



<p>All in all, macOS 26 and iOS 26 introduce a major UI overhaul, which can change the appearance of existing layouts. To help developers, Apple has added UI Compatibility Mode, which lets your apps appear on these new OS versions just as they did on previous releases—no Liquid Glass effects or layout changes. Technically, enabling this mode makes your app behave as if it were compiled with an earlier SDK. While Apple only guarantees this behavior for macOS 26 and iOS 26, it ensures consistency for both debugged and built apps, including those submitted via Publish.</p>



<p>UI Compatibility Mode gives you a choice: enable it to preserve your exact layouts across all OS versions, or leave it off to adopt the new macOS 26 and iOS 26 look and feel, which may require adjusting your UI for some quirks.</p>



<p><em>Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón</em>, <em>Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at <a href="https://twitter.com/xojoes" target="_blank" rel="noreferrer noopener">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Modern and Evolving: macOS and iOS 26 and WinUI in Xojo</title>
		<link>https://blog.xojo.com/2025/12/09/modern-and-evolving-macos-and-ios-26-and-winui-in-xojo/</link>
		
		<dc:creator><![CDATA[Geoff Perlman]]></dc:creator>
		<pubDate>Tue, 09 Dec 2025 16:30:56 +0000</pubDate>
				<category><![CDATA[iOS]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[2025r3]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[macOS 26]]></category>
		<category><![CDATA[macOS Tahoe]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[WinUI]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=15650</guid>

					<description><![CDATA[As the platforms we develop for continue to evolve, so does Xojo. Each year brings new design directions, updated frameworks and refreshed user experience standards&#8230;]]></description>
										<content:encoded><![CDATA[
<p>As the platforms we develop for continue to evolve, so does Xojo. Each year brings new design directions, updated frameworks and refreshed user experience standards across macOS, iOS and Windows. Staying aligned with these changes is essential, not just to keep apps looking modern, but to ensure they feel right at home on every device. In this post, we’ll take a look at how Xojo is adapting to Apple’s latest updates and our ongoing work to bring a modern Windows experience through WinUI.</p>



<h2 class="wp-block-heading">macOS 26 and iOS 26</h2>



<p>Over time, Apple has brought the user experiences of macOS and iOS closer together. macOS 26 and iOS 26, now aligned in version numbers, also share more similarities than ever in their user experience. These updates represent the most significant user experience changes from Apple since iOS was introduced in 2007 and Aqua for macOS seven years earlier. With such a big update, especially when designing elements to work on both large computers displays as well as small smartphone screens, it’s no surprise there’s some tweaking requiring after release. Clearly, Apple is still refining its platforms.</p>



<p>We continue to update Xojo as Apple defines its preferred user experience, ensuring that you can deliver the best possible experience to your users.</p>



<h2 class="wp-block-heading">WinUI</h2>



<p>We are also hard at work upgrading our Windows framework to WinUI, providing a modern user experience for Windows apps. You can see our progress in each release by enabling the Use WinUI (Experimental) option on the Advanced tab in Windows build settings. The “Experimental” label is a reminder that the feature is still evolving, and it will be removed once WinUI is fully ready. Our goal has always been to keep Xojo on a steady path, prepared for whatever challenges lie ahead.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p>On behalf of the entire Xojo team, I can say that we love what we do and we appreciate your support in allowing us to do it. We are Xojo users ourselves (after all, we make Xojo with Xojo) and we enjoy seeing what you make with it. With that in mind, feel free to tell us about your creations. Send your screenshots, descriptions and your story to hello@xojo.com.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Year of Code 2025: April Project, User Interface</title>
		<link>https://blog.xojo.com/2025/04/08/year-of-code-2025-april-project-user-interface/</link>
		
		<dc:creator><![CDATA[Gabriel Ludosanu]]></dc:creator>
		<pubDate>Tue, 08 Apr 2025 15:30:00 +0000</pubDate>
				<category><![CDATA[Community]]></category>
		<category><![CDATA[Desktop]]></category>
		<category><![CDATA[Fun]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Year of Code]]></category>
		<category><![CDATA[#YearofCode]]></category>
		<category><![CDATA[Beginner Tips]]></category>
		<category><![CDATA[GitHub]]></category>
		<category><![CDATA[Listbox]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[UI-Design]]></category>
		<category><![CDATA[User Interface]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=14788</guid>

					<description><![CDATA[April&#8217;s Year of Code theme is all about a great User Interface, I decided to focus on refining the user experience of an existing application.&#8230;]]></description>
										<content:encoded><![CDATA[
<p>April&#8217;s Year of Code theme is all about a great User Interface, I decided to focus on refining the user experience of an existing application. My project involves a user interface revamp of the familiar built-in ToDo desktop app example provided with Xojo.</p>



<p>The goal wasn&#8217;t to add new features but to explore how applying thoughtful UI design principles can significantly enhance the look and feel of an application, making it more visually appealing and cohesive.</p>



<p>Here are some of the key aspects of the UI revamp:</p>



<ul class="wp-block-list">
<li><strong>Design System Foundation:</strong>&nbsp;I started by establishing a basic design system. This involved defining core visual elements to ensure consistency across the entire application interface.</li>



<li><strong>Typography Definition:</strong>&nbsp;Specific styles were defined for how titles and standard text should appear. This helps create a clear visual hierarchy and improves readability.</li>



<li><strong>Consistent Color Palette:</strong>&nbsp;A specific set of colors (Light &amp; Dark mode) was chosen and implemented throughout the project, contributing to a unified and more polished look.</li>



<li><strong>Refined ListBox Appearance:</strong>&nbsp;The standard&nbsp;DesktopListBox&nbsp;control received some visual tweaks to better align with the overall updated aesthetic.</li>
</ul>



<p>The aim was to demonstrate how focusing on UI details can elevate even a simple example application.</p>



<p>Here’s a glimpse of the revamped ToDo app:</p>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-full"><img decoding="async" width="602" height="452" data-id="14792" src="https://blog.xojo.com/wp-content/uploads/2025/04/ToDoOrig-1.jpg" alt="" class="wp-image-14792" srcset="https://blog.xojo.com/wp-content/uploads/2025/04/ToDoOrig-1.jpg 602w, https://blog.xojo.com/wp-content/uploads/2025/04/ToDoOrig-1-300x225.jpg 300w" sizes="(max-width: 602px) 100vw, 602px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="602" height="584" data-id="14793" src="https://blog.xojo.com/wp-content/uploads/2025/04/ToDoFresh-1.jpg" alt="" class="wp-image-14793" srcset="https://blog.xojo.com/wp-content/uploads/2025/04/ToDoFresh-1.jpg 602w, https://blog.xojo.com/wp-content/uploads/2025/04/ToDoFresh-1-300x291.jpg 300w" sizes="auto, (max-width: 602px) 100vw, 602px" /></figure>
</figure>



<p>You can find the complete source code for this UI-enhanced <a href="https://github.com/xolabsro/ToDoFresh" data-type="link" data-id="https://github.com/xolabsro/ToDoFresh" target="_blank" rel="noreferrer noopener">ToDo app project on GitHub</a>. </p>



<p>Stay tuned for more exciting projects as we continue our Year of Code 2025 journey!</p>



<p><em>Gabriel is a digital marketing enthusiast who loves coding with Xojo to create cool software tools for any platform. He is always eager to learn and share new ideas!</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>



<p><strong>Year of Code Project</strong></p>



<ul class="wp-block-list">
<li><a href="https://blog.xojo.com/2025/01/09/year-of-code-2025-kickoff/">Year of Code: Kickoff</a></li>



<li><a href="https://blog.xojo.com/2025/01/15/year-of-code-2025-january-project/" target="_blank" rel="noreferrer noopener">January Project: Desktop Apps</a>&nbsp;|&nbsp;<a href="https://forum.xojo.com/t/year-of-code-2025-january-project-sharing/83927" target="_blank" rel="noreferrer noopener">Forum Discussion</a></li>



<li><a href="https://blog.xojo.com/2025/02/11/year-of-code-2025-february-project/">February Project: Database Apps</a>&nbsp;|&nbsp;<a href="https://forum.xojo.com/t/2025-year-of-code-february" target="_blank" rel="noreferrer noopener">Forum Discussion</a></li>



<li><a href="https://blog.xojo.com/2025/03/05/year-of-code-2025-march-project-web-apps/">March Project: Web Apps</a> | <a href="https://forum.xojo.com/t/2025-year-of-code-march/84474?u=alyssa_foley">Forum Discussion</a></li>



<li><a href="https://blog.xojo.com/2025/04/08/year-of-code-2025-april-project-user-interface/">April Project: User Interface</a> | <a href="https://forum.xojo.com/t/2025-year-of-code-april-user-interface/84926">Forum Discussion</a></li>



<li><a href="https://blog.xojo.com/2025/05/07/year-of-code-2025-may-project-mobile-apps/">May Project: Mobile Apps</a> | <a href="https://forum.xojo.com/t/2025-year-of-code-may-is-mobile/85272">Forum Discussion</a></li>



<li><a href="https://blog.xojo.com/2025/06/10/year-of-code-2025-june-project-cross-platform-code-class/">June Project: Code Sharing</a> | <a href="https://forum.xojo.com/t/2025-year-of-code-june-is-code-sharing/85612">Forum Discussion</a></li>



<li><a href="https://blog.xojo.com/2025/07/10/year-of-code-2025-july-project-charting/">July Project: Charting</a> | <a href="https://forum.xojo.com/t/2025-year-of-code-july-is-charting/85896">Forum Discussion</a></li>



<li><a href="https://blog.xojo.com/2025/08/07/year-of-code-2025-august-project-console-apps/">August Project: Console Apps</a> | <a href="https://forum.xojo.com/t/august-2025-year-of-code-console-apps/86203">Forum Discussion</a></li>



<li><a href="https://blog.xojo.com/2025/09/08/year-of-code-2025-september-project-games/">September Project: Games</a> | <a href="https://forum.xojo.com/t/2025-year-of-code-septgamer">Forum Discussion</a></li>



<li><a href="https://blog.xojo.com/2025/10/13/year-of-code-2025-october-project-multi-platform-communication/">October Project: Multi-Platform</a> | <a href="https://forum.xojo.com/t/2025-year-of-code-october-multi-platform-communication/86717">Forum Discussion</a></li>



<li><a href="https://blog.xojo.com/2025/11/10/year-of-code-2025-november-project-pdf-postcard-generator/">November Project: PDF</a> | <a href="https://forum.xojo.com/t/2025-year-of-code-november-pdf/86969">Forum Discussion</a></li>
</ul>



<p><strong>How to Play:</strong></p>



<p>Each month we&#8217;ll announce a new theme and share an example project of our own. Share your projects to the Xojo Forum thread for that month via GitHub (all the links you need are posted above ↑ ). Learn how to use <a href="https://blog.xojo.com/2024/04/02/using-xojo-and-github/">Xojo and GitHub</a>.</p>



<p><strong>The Prizes:</strong></p>



<p>Monthly winners get $100 at the Xojo store. Every month you submit a project is another chance to win the grand prize. The grand prize is $250 cash plus a Xojo Pro license and a year of GraffitiSuite and will be announce in December. Learn more about the <a href="https://blog.xojo.com/2025/01/09/year-of-code-2025-kickoff/#prizes">prizes</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Use AndroidMobileUserControl to Create Custom Controls</title>
		<link>https://blog.xojo.com/2025/03/25/use-androidmobileusercontrol-to-create-custom-controls/</link>
		
		<dc:creator><![CDATA[Paul Lefebvre]]></dc:creator>
		<pubDate>Tue, 25 Mar 2025 15:30:00 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[2025r1]]></category>
		<category><![CDATA[Control]]></category>
		<category><![CDATA[Declares]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[User Interface]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=14637</guid>

					<description><![CDATA[Xojo for Android has robust Declare and Library support that allows you to call into many native Android libraries and frameworks. With the newly added&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Xojo for Android has robust <a href="https://blog.xojo.com/2024/10/01/android-declare-and-library-enhancements/">Declare and Library support</a> that allows you to call into many native Android libraries and frameworks. With the newly added AndroidMobileUserControl you can also create your own native UI controls as well.</p>



<p>This control is available in the Xojo Library panel and works similarly to iOSMobileUserControl: drag it onto a layout and implement the CreateView event.</p>



<pre class="wp-block-code"><code>Declare Function Button Lib "Kotlin" Alias "android.widget.Button(context as android.content.Context)" (context As Ptr) As Ptr

Var bp As Ptr = Button(App.AndroidContextHandle)

Return bp</code></pre>



<p>The above code uses a Declare to create a native Button and returns it so that it can be displayed in a layout.</p>



<p>By using AndroidMobileUserControl and Declares to access the Android UI library, you can create your own UI controls. I look forward to seeing what the community creates!</p>



<p><em>Paul learned to program in BASIC at age 13 and has programmed in more languages than he remembers, with Xojo being an obvious favorite. When not working on Xojo, you can find him talking about retrocomputing at <a href="https://goto10.substack.com" target="_blank" rel="noreferrer noopener">Goto 10</a> and </em>on Mastodon @lefebvre@hachyderm.io.</p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Popovers for Xojo Desktop, Web and iOS</title>
		<link>https://blog.xojo.com/2024/03/26/popovers-for-xojo-desktop-web-and-ios/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Tue, 26 Mar 2024 15:27:47 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Desktop]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Raspberry Pi]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Xojo Cloud]]></category>
		<category><![CDATA[2024r1]]></category>
		<category><![CDATA[Multi-Platform Development]]></category>
		<category><![CDATA[Popovers]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[User Interface]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=12707</guid>

					<description><![CDATA[Starting with Xojo 2024r1 there's a new Window type in Xojo's UI/UX bag: Popovers. Popovers are kind of a Modal window with a more transient behavior and associated with a Parent control. A Popover will display the chosen content or layout, the same as when you design the user interface of a window or a Container control that will be included as part of another more complex design or displayed at runtime.]]></description>
										<content:encoded><![CDATA[
<p>Starting with Xojo 2024r1 there&#8217;s a new Window type in Xojo&#8217;s UI/UX bag: Popovers. Popovers are kind of a Modal window with a more transient behavior and associated with a Parent control. A Popover will display the chosen content or layout, the same as when you design the user interface of a window or a Container control that will be included as part of another more complex design or displayed at runtime.</p>



<span id="more-12707"></span>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1024" height="558" src="https://blog.xojo.com/wp-content/uploads/2024/03/Popover-1024x558.png" alt="" class="wp-image-12708" srcset="https://blog.xojo.com/wp-content/uploads/2024/03/Popover-1024x558.png 1024w, https://blog.xojo.com/wp-content/uploads/2024/03/Popover-300x164.png 300w, https://blog.xojo.com/wp-content/uploads/2024/03/Popover-768x419.png 768w, https://blog.xojo.com/wp-content/uploads/2024/03/Popover-1536x837.png 1536w, https://blog.xojo.com/wp-content/uploads/2024/03/Popover-2048x1116.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p>And what do we mean by the transitory character of Popover windows? Well, and here comes one of the first differences from Modal windows. When a Popover is visible and the user clicks or taps on any other element of the graphical interface not contained in the Popover itself it will close, hence transitory. So, you don&#8217;t have to include the typical &#8220;Close window&#8221; button in a Popover (though you can), since it will close when the user clicks outside of it, i.e. when the Popover loses focus.</p>



<h3 class="wp-block-heading">Where are the Popover Window Contents?</h3>



<p>Where do you define the content displayed in a Popover window? While in your Web app, you can do it on any Container control added to the project. In the case of Desktop and iOS apps, you can do it on either the designs of a Container Control or any Window or Screen added to the project.</p>



<p>For example, here you can see that the content shown as a Popover in the previous screenshot is actually that of a Window (Window2) added to the project:</p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1024" height="558" src="https://blog.xojo.com/wp-content/uploads/2024/03/PopoverUI-1024x558.png" alt="" class="wp-image-12709" srcset="https://blog.xojo.com/wp-content/uploads/2024/03/PopoverUI-1024x558.png 1024w, https://blog.xojo.com/wp-content/uploads/2024/03/PopoverUI-300x163.png 300w, https://blog.xojo.com/wp-content/uploads/2024/03/PopoverUI-768x418.png 768w, https://blog.xojo.com/wp-content/uploads/2024/03/PopoverUI-1536x837.png 1536w, https://blog.xojo.com/wp-content/uploads/2024/03/PopoverUI-2048x1116.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p>This introduces additional flexibility allowing your app&#8217;s logic to decide when to display a Window or Container instance as you have been doing until now, or display it as a Popover.</p>



<h3 class="wp-block-heading">Showing a Popover</h3>



<p>Displaying a Popover is very straightforward, whether it is created from a Container or a Window, the method is the same:</p>



<pre class="wp-block-preformatted">DesktopContainer.ShowPopover(parentControl As DesktopUIControl, facing As DesktopWindow.DisplaySides = DesktopWindow.DisplaySides.Bottom, detachable As Boolean = True)</pre>



<p>The explanation of the expected parameters is as follows:</p>



<ul class="wp-block-list">
<li><strong>ParentControl:</strong> The control that will act as the parent, or on which the Popover will be pointing to.</li>



<li><strong>Facing:</strong> The direction in which the Popover will point on the parent control; by default it will appear under the parent control, but you can use any of the values available in the DesktopWindow.DisplaySides enumerator (or the iOS equivalent).</li>



<li><strong>Detachable:</strong> This value only applies to macOS Popovers, since said operating system has the ability for the user to &#8220;detach&#8221; the Popover from the parent control as long as this value is defined as True. To detach, drag the Popover with the mouse cursor.</li>
</ul>



<p>Let&#8217;s say we have a window called Window2 and a button called MyButton. In the Pressed event of MyButton we can use the following lines of code to display Window2 as a Popover:</p>



<pre class="wp-block-preformatted">Var w As New Window2
w.ShowPopover(me)</pre>



<p>And that&#8217;s all!</p>



<figure class="wp-block-image is-style-default"><img loading="lazy" decoding="async" width="1280" height="720" src="https://blog.xojo.com/wp-content/uploads/2024/03/PopoverDettach.gif" alt="" class="wp-image-12710"/></figure>



<h3 class="wp-block-heading">Platform Differences</h3>



<p>In the previous section we already pointed out the first: macOS is the only operating system that acts on the value indicated in the Detachable parameter. But there are some other considerations to keep in mind so you don&#8217;t get caught off guard:</p>



<ul class="wp-block-list">
<li><strong>Beyond the limits.</strong> Although in Windows and macOS Popovers can exceed the limits of the window on which the parent control is located, the position of the popover in Linux is restricted to the limits of the window that contains the parent control. This is the same for iOS and for Web pages.</li>



<li><strong>iPhone and iPad.</strong> When a Popover is displayed on an iPhone, it will look like a modal window; while if the same application is run on an iPad, the appearance will be the typical one expected from Popovers: the window pointing to the parent control in the indicated direction.</li>



<li><strong>On the Web.</strong> The contents of a Popover are those defined in a Container control, while on the rest of the platforms you can use both Container controls and Windows / Screens.</li>
</ul>



<h3 class="wp-block-heading">Why the Popover doesn&#8217;t &#8220;point&#8221; in the configured direction?</h3>



<p>By default it will try to do so according to the value that has been set in the &#8220;facing&#8221; parameter, but if it does not find enough space on the margins of the screen, then it will be displayed on the next side of the parent control in which there is available space for display the Popover in its full width and height; This is true on macOS, Linux, Web and iOS.</p>



<h3 class="wp-block-heading">Can I reuse a Popover?</h3>



<p>No, You can not. Whether you use a Container control or a window as the source of the UI design to be displayed by the Popover, do not lose sight of the fact that the Popover is just another type of window; and therefore behaves as such. That is, once it is closed either because it has lost focus or because you have closed it explicitly through code invoking the Close method, all the displayed controls and the rest of the internal structures will be closed / invalidated, so that although the instance If a Popover is not Nil (because, for example, you keep a reference to the window or container instance used as the UI source), you will not be able to invoke the ShowPopover method again on said instance but you will have to create a new instance of the Container/ Window used as the source of the UI to be displayed by the Popover.</p>



<h3 class="wp-block-heading">How can I communicate with the UI elements contained in the Popover?</h3>



<p>You would do so just as you would do with any other type of window that you have been using so far in your Xojo projects.</p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter"><img loading="lazy" decoding="async" width="1280" height="720" src="https://blog.xojo.com/wp-content/uploads/2024/03/PopoverComm.gif" alt="" class="wp-image-12712"/></figure>
</div>


<h3 class="wp-block-heading">Conclusion</h3>



<p>Without a doubt, Popovers are a new way to improve the design of your apps&#8217; user interfaces, providing a more direct relationship between the user interface elements displayed in the Popover and the &#8220;parent&#8221; control in charge of displaying it. Furthermore, since you can use any window or container you want as the source of the UI to be displayed by the Popover, you will have greater flexibility about when you want to display them in a Popover or display them using any other of the available window types or, in the case of Containers, embedding them as part of other UI elements at runtime.</p>



<p><em>Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón</em>, <em>Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at <a href="https://twitter.com/xojoes" target="_blank" rel="noreferrer noopener">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Tutorial: Design a Control to Dynamically Preview Images and PDF Files</title>
		<link>https://blog.xojo.com/2024/03/11/tutorial-design-a-control-to-dynamically-preview-images-and-pdf-files/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Mon, 11 Mar 2024 15:00:00 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Desktop]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Composition]]></category>
		<category><![CDATA[ContainerControl]]></category>
		<category><![CDATA[Control]]></category>
		<category><![CDATA[Multi-Platform Development]]></category>
		<category><![CDATA[PDF]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=12601</guid>

					<description><![CDATA[In this tutorial learn to design a cross-platform control that dynamically previews images and PDF files. Files can dragged and dropped onto the control, opened from the standard file selection dialog, and, in the case of images, added using Copy and Paste. The file path will be displayed below the addendum file. ]]></description>
										<content:encoded><![CDATA[
<p>A few days ago, I received a request from a user about how to solve a problem he was facing in a control for one of the desktop applications used by his company. This is the scenario:</p>



<ul class="wp-block-list">
<li>The control should show previews of images and PDF documents.</li>



<li>The documents to be displayed can be dragged and dropped onto the control, or opened from the standard file selection dialog.</li>



<li>In the case of images, they can also be added to the control using Copy and Paste.</li>



<li>In any of the above cases, the path of the file in question must be received so that future actions can be carried out.</li>
</ul>



<p>As an additional point, since we are using Xojo, the control will be cross-platform and functional on macOS, Windows and Linux.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><a href="https://drive.google.com/file/d/1TCFB8fNq2bZu7i1KMhWYCV26LdXK6Ykz/view?usp=share_link">Download the Example Project</a>.</p>
</blockquote>



<h2 class="wp-block-heading">Preparation</h2>



<p>Taking into account these requirements, as well as considering that the same problem may have more than one solution, this tutorial will show you how to create a control using the <a href="https://en.wikipedia.org/wiki/Composition_over_inheritance">Composition technique</a>. Using this technique, several graphical interface controls will be used internally and their use will be transparent to users who use it globally, either when creating their own applications or when using the control on any desktop platform.</p>



<p>When it comes to creating a control using the Composition technique, the DesktopContainerControl is the best candidate. A new ContainerControl-based class would internally use the following core controls:</p>



<ol class="wp-block-list">
<li>The DesktopImageWell control which is ideal for displaying images. </li>



<li>The DesktopHTMLViewer control which is ideal for displaying the preview of PDF documents.</li>
</ol>



<p>Now, while DesktopImageWell supports displaying images directly using Drag and Drop, this is not the case with the DesktopHTMLViewer control; so if the user of the control tried to drag and drop a PDF document or image when the HTMLViewer is displaying the control, it wouldn&#8217;t work.</p>



<p>To solve this situation it is common to add a third control. We&#8217;ll use a DesktopCanvas that will be, at all times, the top layer regardless of which underlying control (either the ImageWell or the HTMLViewer) is displayed. Thus, the DesktopCanvas would capture the event corresponding to the user dragging a file onto the global control (the class based on ContainerControl). Since it is transparent, it will not prevent the preview of the image or PDF file to be seen in the bottom layer control, at least on macOS.</p>



<p>But the Canvas is not transparent on Windows, in this case we need to use conditional compilation at various points in the class to modify the user interface of the main ContainerControl so that it adds a special area located under the controls preview (ImageViewer or HTMLViewer), and which will be used by the user of the control to drag and drop the corresponding files. For this we will use an additional DesktopCanvas.</p>



<p>Of course, we will also have to add a button to our control that will be responsible for opening the standard file selection dialog box so that the user can choose the file to preview.</p>



<p>To deal with another small difference between macOS and Windows, we will add a DesktopRectangle to be used as the base layer of the control (Z axis), so that it displays the typical Focus ring when the control is active and selected.</p>



<h2 class="wp-block-heading">Designing the Control</h2>



<p>With all that in mind, start a new Desktop project in Xojo. Drag a DesktopContainer from the Library onto the Navigator. It will look like this:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="774" src="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-1-1024x774.png" alt="" class="wp-image-12602" srcset="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-1-1024x774.png 1024w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-1-300x227.png 300w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-1-768x581.png 768w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-1-1536x1161.png 1536w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-1-2048x1548.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>With the new Desktop Container1 instance selected in the Navigator, use the Inspector Panel to change the following values:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> ImagePDFContainer </li>



<li><strong>Size &gt; Width</strong>: 220 </li>



<li><strong>Size &gt; Height:</strong> 200</li>
</ul>



<p>Next, add the Drag and Drop area which, remember, will be shown only when the control is executed on Windows. To do this, drag a DesktopCanvas from the Library and drop it in the area of the Layout Editor corresponding to the Design Editor, placing it right under the container for our own convenience.</p>



<p>With Canvas1 selected, use the Inspector Panel to change the following values:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> DropArea</li>



<li><strong>Position &gt; Left:</strong> 1</li>



<li><strong>Position &gt; Top:</strong> 221</li>



<li><strong>Position &gt; Width:</strong> 216</li>



<li><strong>Position &gt; Height:</strong> 100</li>
</ul>



<p>The design should look like this:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="774" src="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-2-1024x774.png" alt="" class="wp-image-12603" srcset="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-2-1024x774.png 1024w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-2-300x227.png 300w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-2-768x581.png 768w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-2-1536x1161.png 1536w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-2-2048x1548.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Now, add the background layer. This is the layer that will be in charge of displaying the focus ring for the control in Windows. To do this, drag a DesktopRectangle from the Library and drop it on the ContainerControl in the Layout Editor. The ContainerControl should show a red box indicating that the dragged control will be contained as a child control in the Container itself. Next, with DesktopRectangle1 still selected in the Layout Editor, use the Inspector Panel to modify the following values:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> BacktroundRect</li>



<li><strong>Position &gt; Left:</strong> 0</li>



<li><strong>Position &gt; Top:</strong> 0</li>



<li><strong>Position &gt; Width:</strong> 220</li>



<li><strong>Position &gt; Height:</strong> 200</li>



<li><strong>Locking:</strong> Lock all four padlocks.</li>
</ul>



<p>Next, add the button responsible for displaying the standard dialog box for selecting the file to preview. Drag a DesktopPushButton from the Library and drop it onto the bottom of the Container in the Layout Editor. The Container should display a red box to indicate that the button will be added as a child control in the Container itself.</p>



<p>Then, with Button1 still selected in the Layout Editor, use the associated Inspector Panel to change the following values:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> OpenFileButton</li>



<li><strong>Position &gt; Left:</strong> 0</li>



<li><strong>Position &gt; Top:</strong> 0</li>



<li><strong>Position &gt; Width:</strong> 178</li>



<li><strong>Position &gt; Height:</strong> 22</li>



<li><strong>Locking:</strong> Closes the left, right and bottom locks. Open the lock on the top edge.</li>



<li><strong>Mac Button Style:</strong> Recessed</li>



<li><strong>Caption:</strong> Open File…</li>
</ul>



<p>At this point, the control layout should look something like this:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="774" src="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-3-1024x774.png" alt="" class="wp-image-12604" srcset="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-3-1024x774.png 1024w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-3-300x227.png 300w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-3-768x581.png 768w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-3-1536x1161.png 1536w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-3-2048x1548.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Now, add the instance of the DesktopImageViewer control responsible for previewing the images. As in previous steps, drag the DesktopImageViewer control from the Library and drop it on the Layout Editor, in the upper right part of the Container; then, with ImageViewer1 still selected, use the associated Inspector Panel to change the following values:</p>



<ul class="wp-block-list">
<li><strong>Name: </strong>ImagePreviewer</li>



<li><strong>Position &gt; Left: </strong>238</li>



<li><strong>Position &gt; Top:</strong> -219</li>



<li><strong>Position &gt; Width:</strong> 218</li>



<li><strong>Position &gt; Height:</strong> 198</li>



<li><strong>Locking:</strong> Lock all four padlocks.</li>
</ul>



<p>Drag a DesktopHTMLViewer from the Library onto the free area of the Layout Editor, just below the ImageViewer added in the previous step; Then, with HTMLViewer1 still selected in the Layout Editor, use the associated Inspector Panel to modify the following values:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> HTMLPDF</li>



<li><strong>Position &gt; Left:</strong> 238</li>



<li><strong>Position &gt; Top:</strong> 0</li>



<li><strong>Position &gt; Width:</strong> 218</li>



<li><strong>Position &gt; Height:</strong> 198</li>



<li><strong>Locking: </strong>Lock all four padlocks.</li>
</ul>



<p>At this point, the control layout should look something like this:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="774" src="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-4-1024x774.png" alt="" class="wp-image-12605" srcset="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-4-1024x774.png 1024w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-4-300x227.png 300w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-4-768x581.png 768w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-4-1536x1161.png 1536w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-4-2048x1548.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Finally, add the overlay to be used only when the control is executed on macOS and that is responsible for capturing the action of &#8220;Drag and Drop&#8221; files by the user. Drag a new DesktopCanvas over the Container in the Layout Editor. The Container should display a red box to indicate that the new control is being added as a child of the Container itself. With Canvas1 still selected in the Layout Editor, use the associated Inspector Panel to modify the following values:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> CanvasOverlay</li>



<li><strong>Position &gt; Left:</strong> 1</li>



<li><strong>Position &gt; Top:</strong> 1</li>



<li><strong>Position &gt; Width:</strong> 218</li>



<li><strong>Position &gt; Height:</strong> 179</li>



<li><strong>Locking:</strong> Lock all four padlocks.</li>
</ul>



<p>To make sure that all the &#8220;layers&#8221; (order of the controls on the Z axis) are as we expect, click on the &#8220;Show Tab Order&#8221; button in the Layout Editor toolbar. If they do not match the order shown in the image below, drag and drop each element to the correct position in the list:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="774" src="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-5-1024x774.png" alt="" class="wp-image-12606" srcset="https://blog.xojo.com/wp-content/uploads/2024/02/Captura-5-1024x774.png 1024w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-5-300x227.png 300w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-5-768x581.png 768w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-5-1536x1161.png 1536w, https://blog.xojo.com/wp-content/uploads/2024/02/Captura-5-2048x1548.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h2 class="wp-block-heading">Add Functionality</h2>



<p>With the design of the control now complete, it is time to add its functionality. To do this, select ImagePDFContainer in the Navigator and add the following properties along with the values indicated in the Inspector Panel:</p>



<p>The first will be in charge of containing the message to be displayed in the &#8220;Drag and Drop&#8221; area:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> DropFileMessage</li>



<li><strong>Type:</strong> String </li>



<li><strong>Scope:</strong> Public</li>
</ul>



<p>The second will be the property in charge of storing the reference to the file (FolderItem instance) whose image/PDF is being previewed:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> FileDropped</li>



<li><strong>Type:</strong> FolderItem </li>



<li><strong>Scope:</strong> Private</li>
</ul>



<p>The last property will be responsible for containing the color to be used as the focus ring:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> FocusColor</li>



<li><strong>Type:</strong> Color </li>



<li><strong>Scope:</strong> Public</li>
</ul>



<p>Next, add the events that the control needs to consume for its operation. With ImagePDFContainer still selected in the Navigator, add the following Event Handlers along with the associated code:</p>



<h4 class="wp-block-heading">Opening:</h4>



<pre id="Xojo" class="wp-block-code"><code>HTMLPDF.Visible = False
ImagePreviewer.Visible = False

#If TargetWindows Then
  DropArea.Top = Me.Height - 50
  DropArea.Height = 50
  DropArea.Width = BackgroundRect.Width
  DropArea.Left = BackgroundRect.Left
  BackgroundRect.Height = BackgroundRect.Height - 50
  
  HTMLPDF.Height = BackgroundRect.Height - 2
  ImagePreviewer.Height = BackgroundRect.Height - 2
#EndIf

RaiseEvent Opening</code></pre>



<h4 class="wp-block-heading">MouseDown:</h4>



<pre id="Xojo" class="wp-block-code"><code>Me.SetFocus
Return True</code></pre>



<h4 class="wp-block-heading">FocusReceived:</h4>



<pre class="wp-block-code"><code>#If TargetWindows Then
  FocusColor = Color.Blue
  BackgroundRect.BorderColor = FocusColor
  DropArea.Refresh
#EndIf</code></pre>



<h4 class="wp-block-heading">FocusLost:</h4>



<pre class="wp-block-code"><code>#If TargetWindows Then
  FocusColor = Color.Black
  BackgroundRect.BorderColor = FocusColor
  DropArea.Refresh
#EndIf</code></pre>



<p>Since the Opening event is used by our ImagePDFContainer subclass, add an event definition with the same name so that instances created from it can also add their own Opening event handler and include any additional code to execute as desired.</p>



<p>Then, add an additional event definition (FileDropped) that will be the one sent by the ImagePDFContainer subclass to the instances created from it, and that implement it, to pass them as a parameter the FolderItem corresponding to the file opened / dragged and dropped / or , in the case of images, that have been pasted on the control.</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> FileDropped</li>



<li><strong>Parameters:</strong> file As FolderItem</li>
</ul>



<p>Since we want to support pasting images onto the control, we also need to add a MenuHandler to the ImagePDFContainer subclass. To do this, with ImagePDFContainer still selected in the Navigator, select the option Add to &#8220;ImagePDFContainer&#8221; &gt; Menu Handler&#8230;</p>



<p>Use the following values in the associated Inspector Panel:</p>



<ul class="wp-block-list">
<li><strong>MenuItem Name:</strong> EditPaste</li>
</ul>



<p>And add the following code in the Code Editor associated with the Menu Handler:</p>



<pre id="Xojo" class="wp-block-code"><code>Var pb As New Clipboard
If pb.PictureAvailable Then
  Var f As FolderItem = SpecialFolder.Temporary.Child("temp-pict.png")
  If f.Exists Then f.Remove
  If f &lt;&gt; Nil Then
    pb.Picture.Save(f, Picture.Formats.PNG)
    FileDropped = f
    PreviewFile(FileDropped)
  End If
  Return True
End If

Return False</code></pre>



<p>To complete this section, add a new method to ImagePDFContainer and use the following values in the associated Inspector Panel:</p>



<ul class="wp-block-list">
<li><strong>Method Name:</strong> PreviewFile</li>



<li><strong>Parameters:</strong> f As FolderItem</li>
</ul>



<p>Add the following code in the associated Code Editor:</p>



<pre id="Xojo" class="wp-block-code"><code>FileDropped = f

If f &lt;> Nil Then
  
  If FileDropped.Name.EndsWith(".pdf") Then
    ImagePreviewer.Visible = False
    HTMLPDF.Visible = True
    
    HTMLPDF.Top = BackgroundRect.Top + 1
    HTMLPDF.Left = BackgroundRect.Left + 1
    
    #If TargetWindows Then
      HTMLPDF.Height = BackgroundRect.Height - OpenFileButton.Height
    #Else
      HTMLPDF.Height = Self.Height - OpenFileButton.Height
    #EndIf
    
    HTMLPDF.LoadPage(FileDropped)
    
  Else
    
    Var p As Picture = Picture.Open(FileDropped)
    
    If p &lt;> Nil Then
      ImagePreviewer.Top = BackgroundRect.Top + 1
      ImagePreviewer.Left = BackgroundRect.Left + 1
      
      #If TargetWindows Then
        ImagePreviewer.Height = BackgroundRect.Height - OpenFileButton.Height
      #Else
        ImagePreviewer.Height = Self.Height - OpenFileButton.Height
      #EndIf
      
      ImagePreviewer.Image = p
      HTMLPDF.Visible = False
      ImagePreviewer.Visible = True
      
    End If
    
  End If
  
  RaiseEvent FileDropped(FileDropped)
  
Else
  HTMLPDF.Visible = False
  ImagePreviewer.Visible = False
End If</code></pre>



<h2 class="wp-block-heading">Add Functionality to Controls</h2>



<p>Now it&#8217;s time to add functionality to the controls. Select the CanvasOverlay item in the Navigator and add the following Event Handlers along with the code given below:</p>



<h4 class="wp-block-heading">Opening:</h4>



<pre class="wp-block-code"><code>Me.AcceptFileDrop("application/pdf")
Me.AcceptFileDrop("image/png")
Me.AcceptFileDrop("image/jpg")

#If TargetWindows Then
  Me.Visible = False
#EndIf</code></pre>



<h4 class="wp-block-heading">DropObject:</h4>



<pre class="wp-block-code"><code>#Pragma Unused action

If obj.FolderItemAvailable Then
  PreviewFile(obj.FolderItem)
End If</code></pre>



<h4 class="wp-block-heading">MouseDown:</h4>



<pre class="wp-block-code"><code>#Pragma Unused x
#Pragma Unused y

Self.SetFocus</code></pre>



<p>Now select the DropArea item in the Navigator and add the following Event Handlers along with the code indicated below:</p>



<h4 class="wp-block-heading">Opening:</h4>



<pre class="wp-block-code"><code>Me.AcceptFileDrop("application/pdf")
Me.AcceptFileDrop("image/png")
Me.AcceptFileDrop("image/jpg")

#If TargetMacOS Then
  Me.Visible = False
#EndIf</code></pre>



<h4 class="wp-block-heading">DropObject:</h4>



<pre class="wp-block-code"><code>#Pragma Unused action

If obj.FolderItemAvailable Then
  PreviewFile(obj.FolderItem)
End If</code></pre>



<h4 class="wp-block-heading">Paint:</h4>



<pre class="wp-block-code"><code>#Pragma Unused areas

g.DrawingColor = FocusColor
g.PenSize = 2.0
g.DrawRectangle(0, 0, g.Width, g.Height)
g.PenSize = 1.0

If DropFileMessage &lt;> "" Then
  
  g.DrawingColor = Color.Black
  
  Var textLength As Double = g.TextWidth(DropFileMessage)
  Var x, y As Double
  
  x = Me.Width / 2 - textLength / 2
  y = Me.Height / 2 + g.TextHeight / 2
  
  g.DrawText(DropFileMessage, x, y)
  
End If</code></pre>



<p>Now select the HTMLPDF item in the Navigator and add the Event Handlers along with the code indicated below:</p>



<h4 class="wp-block-heading">MouseDown:</h4>



<pre class="wp-block-code"><code>#Pragma Unused x
#Pragma Unused y

Self.SetFocus</code></pre>



<p>Next, select the ImagePreviewer item in the Navigator and add the following Event Handlers along with the code below:</p>



<h4 class="wp-block-heading">MouseDown:</h4>



<pre class="wp-block-code"><code>#Pragma Unused x
#Pragma Unused y

Self.SetFocus</code></pre>



<p>Finally, select the OpenFileButton item in the Navigator and add the following Event Handlers along with the code indicated below:</p>



<h4 class="wp-block-heading">Pressed:</h4>



<pre class="wp-block-code"><code>Var f As FolderItem = FolderItem.ShowOpenFileDialog("")

If f &lt;> Nil Then
  Self.PreviewFile(f)
End If</code></pre>



<h2 class="wp-block-heading">Testing the ImagePDFContainer Control</h2>



<p>We have completed the design and added the required functionality to our control, now it is time to add an instance to the project window so we can test its operation.</p>



<p>Select Window1 in the Navigator so that the associated Layout Editor is displayed. Next drag ImagePDFContainer from the Navigator and drop it onto the Layout Editor, using the following values in the associated Inspector Panel:</p>



<ul class="wp-block-list">
<li><strong>Size &gt; Width: </strong>220</li>



<li><strong>Size &gt; Height:</strong> 200</li>



<li><strong>Locking:</strong> Lock all four padlocks</li>



<li><strong>Appearance &gt; Allow Focus Ring:</strong> Enabled </li>



<li><strong>Behavior &gt; Allow Focus: </strong>Enabled.</li>



<li><strong>Behavior &gt; Allow Tabs:</strong> Enabled.</li>
</ul>



<p>With ImagePDFContainer1 selected in the Navigator, add the following Event Handlers along with the code below:</p>



<h4 class="wp-block-heading">Opening:</h4>



<pre class="wp-block-code"><code>Me.DropFileMessage = "Drop Files Here"</code></pre>



<h4 class="wp-block-heading">FileDropped:</h4>



<pre class="wp-block-code"><code>LastFolderItemNameLabel.Text = file.NativePath</code></pre>



<p>As you can see, this is referring to the LastFolderItemNameLabel control that we have not yet added to the window layout yet; So, let&#8217;s do that.</p>



<p>Select Window1 in the Navigator to access the associated Layout Editor. Drag a Label control from the Library and drop it onto the bottom of the window in the Layout Editor, then use the following values in the associated Inspector Panel:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> Label1</li>



<li><strong>Position &gt; Left:</strong> 28</li>



<li><strong>Position &gt; Top: </strong>360</li>



<li><strong>Position &gt; Width:</strong> 150</li>



<li><strong>Position &gt; Height:</strong> 20</li>



<li><strong>Locking:</strong> Lock the left and bottom padlock. Unlock the top and right locks.</li>



<li><strong>Text:</strong> Last FolderItem Path:</li>
</ul>



<p>Add a second Label from the Library to the right of the previous one, using the following values in the associated Inspector Panel:</p>



<ul class="wp-block-list">
<li><strong>Name:</strong> LastFolderItemNameLabel</li>



<li><strong>Position &gt; Left: </strong>190</li>



<li><strong>Position &gt; Top:</strong> 360</li>



<li><strong>Position &gt; Width:</strong> 390</li>



<li><strong>Position &gt; Height:</strong> 20</li>



<li><strong>Locking: </strong>Locks the left, bottom and right padlocks. Unlock the top lock.</li>



<li><strong>Text:</strong> (empty)</li>
</ul>



<h2 class="wp-block-heading">Run the Application</h2>



<p>Ready! Run the application and try dragging and dropping image files (JPEG or PNG), as well as PDF files on the control. You should see the change on the fly, showing the most appropriate viewer for each type of file. It will also display the path of the file at the bottom of the window.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="886" src="https://blog.xojo.com/wp-content/uploads/2024/02/Final-1024x886.png" alt="" class="wp-image-12607" srcset="https://blog.xojo.com/wp-content/uploads/2024/02/Final-1024x886.png 1024w, https://blog.xojo.com/wp-content/uploads/2024/02/Final-300x260.png 300w, https://blog.xojo.com/wp-content/uploads/2024/02/Final-768x665.png 768w, https://blog.xojo.com/wp-content/uploads/2024/02/Final-1536x1329.png 1536w, https://blog.xojo.com/wp-content/uploads/2024/02/Final.png 1648w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>You can also click on the button to select the file to display or try copying images and pasting them directly on the control. If you do this, a temporary file will be created so that one of the initial requirements is satisfied: being able to continue working with the file corresponding to the image or PDF document.</p>



<p>As I mentioned at the beginning, this is just one of the possible implementations. I hope you have learned a few things along the way in, for example:</p>



<ul class="wp-block-list">
<li>Redefine Events consumed by a base class.</li>



<li>Create your own Class Events and how to launch them to &#8220;pass&#8221; information to the instances created from said class.</li>



<li>Capture and work with Menu Handlers.</li>



<li>Use of Conditional Compilation so that certain sections of code run only on one platform or another.</li>



<li>And, of course, how to make several UI controls cooperate and present themselves as a single control to the developer and end user who are going to use them.</li>
</ul>



<p>I hope you found it interesting. You are welcome to modify and expand the project to better suit your purposes!</p>



<p>Have fun and keep coding with Xojo!</p>



<p><em>Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón</em>, <em>Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at <a href="https://twitter.com/xojoes" target="_blank" rel="noreferrer noopener">@XojoES</a> or on the <a href="https://forum.xojo.com/u/javier_menendez/summary" target="_blank" rel="noreferrer noopener">Xojo Forum</a>.</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Detecting Modifier Keys</title>
		<link>https://blog.xojo.com/2020/02/19/detecting-modifier-keys/</link>
		
		<dc:creator><![CDATA[Paul Lefebvre]]></dc:creator>
		<pubDate>Wed, 19 Feb 2020 10:00:00 +0000</pubDate>
				<category><![CDATA[Tips]]></category>
		<category><![CDATA[Timers]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=6589</guid>

					<description><![CDATA[Sometimes it is necessary, or at least user-friendly, to adjust your interface when the user holds down modifier keys. ]]></description>
										<content:encoded><![CDATA[
<p>Sometimes it is necessary, or at least user-friendly, to adjust your interface when the user holds down modifier keys. For example, iTunes changes its &#8220;Previous Track&#8221; button from a rewind icon to a Genius Shuffle icon when the option key is held down. The goal is to inform the user that option-clicking the button will perform a different task.</p>



<p>At first glance you might think that simply looking for the option key in a KeyDown event will do the trick. The problem is KeyDown/KeyUp does not get called for modifier keys. The solution is to use a Timer to detect the Option/Alt key, though it could be adapted to read any of the modifier keys.</p>



<p>First of all, we need to decide whether to create a Timer embedded on a Window, or to create a subclass. Either technique will work, but the subclass creates reusable code, something I always recommend. Also, the subclass will allow you to call events which can come in handy.</p>



<p>Start by creating a new class called &#8220;OptionTimer&#8221; whose super is &#8220;Timer&#8221;. Next, add a property &#8220;Pressed As Boolean&#8221;, an event definition &#8220;KeyDown&#8221;, and a second event definition &#8220;KeyUp&#8221; to OptionTimer. Lastly add the Action event handler with the following code:</p>



<pre class="wp-block-preformatted">If Keyboard.AsyncAltKey = True And Pressed = False Then
  Pressed = True
  RaiseEvent KeyDown
ElseIf KeyBoard.AsyncAltKey = False And Pressed = True Then
  Pressed = False
  RaiseEvent KeyUp
End If</pre>



<p>That&#8217;s it for code. Now go to your Window, place a Timer on it and set the super to &#8220;OptionTimer&#8221; and you can insert code into the events for that timer. You&#8217;ll also want to adjust the period of the timer to something small such as 200 to make sure the events are responsive.</p>



<p>To test this, add a Label to the Window which will be used to display different text when the Option key is held down. In the Timer subclass, put this code in the KeyDown event:</p>



<pre class="wp-block-preformatted">Label1.Value = "You are pressing Option."</pre>



<p>And in the KeyUp event put this code:</p>



<pre class="wp-block-preformatted">Label1.Value = "Normal Text"</pre>



<p>Run the project and watch the text change when you hold and release the Option/Alt key.</p>



<p class="has-small-font-size"><em>*Updated from an original post written by Thom McGrath.</em></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Updating the User Interface with the New Thread Class</title>
		<link>https://blog.xojo.com/2019/11/18/updating-the-ui-with-the-new-thread-class/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Mon, 18 Nov 2019 10:00:12 +0000</pubDate>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Threads]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[User Interface]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=6263</guid>

					<description><![CDATA[With Xojo 2019R2, everything related to updating the UI is much simpler thanks to the new UserInterfaceUpdate event in the Thread class.]]></description>
										<content:encoded><![CDATA[<p>Xojo 2019R2 has a lot of new features and enhancements, including the simplification of updating the User Interface in apps from threads running in combination with the main app thread. Doing that in previous releases required the use of a thread in combination with a Timer, for example.<span id="more-6263"></span></p>
<p>With Xojo 2019R2, everything related to updating the UI is much simpler thanks to the new <code>UserInterfaceUpdate</code> event in the Thread class. This provides, as an Array of Dictionaries, all the values we need to pass along from the <code>Run</code> event of the running Thread.</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-6264 size-large" src="https://blog.xojo.com/wp-content/uploads/2019/11/Xojo-Threads-API-2-1-1024x751.png" alt="" width="1024" height="751" srcset="https://blog.xojo.com/wp-content/uploads/2019/11/Xojo-Threads-API-2-1-1024x751.png 1024w, https://blog.xojo.com/wp-content/uploads/2019/11/Xojo-Threads-API-2-1-300x220.png 300w, https://blog.xojo.com/wp-content/uploads/2019/11/Xojo-Threads-API-2-1-768x563.png 768w, https://blog.xojo.com/wp-content/uploads/2019/11/Xojo-Threads-API-2-1.png 1456w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<p>In order to add new values to these dictionaries, we only need to call the <code>AddUserInterfaceUpdate</code> method, providing as parameter a <code>Pair</code>.</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-6265 size-large" src="https://blog.xojo.com/wp-content/uploads/2019/11/Xojo-Thread-API-2-Project-1024x612.png" alt="" width="1024" height="612" srcset="https://blog.xojo.com/wp-content/uploads/2019/11/Xojo-Thread-API-2-Project-1024x612.png 1024w, https://blog.xojo.com/wp-content/uploads/2019/11/Xojo-Thread-API-2-Project-300x179.png 300w, https://blog.xojo.com/wp-content/uploads/2019/11/Xojo-Thread-API-2-Project-768x459.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<p>The first (left) value of this pair will be the one acting as the Key for the Dictionary, while the second value of the pair (right) will be the value itself we want to forward to the main thread in order to update our user interface.</p>
<p>In addition, the overloaded <code>AddUserInterfaceUpdate</code> method also accepts a Dictionary as a parameter.</p>
<p>The two ways we can use the new thread class are the same available in previous releases:</p>
<ul>
<li>Draging and dropping an object from the Library panel to the Tray in the Window Layout, so the IDE creates a new instance that we can use to implement the <code>Run</code> and, now, also the <code>UserInterfaceUpdate</code> events. The <code>Run</code> event is the one intended to run the code usually associated with a long task, so it doesn&#8217;t <em>freeze</em> the responsiveness of the rest of the app (mainly the user interaction or user interface refreshes). The <code>UserInterfaceUpdate</code> event is the new Event whose parameter will provide all the data we are interested in previously added from the <code>Run</code> event calling the <code>AddUserInterfaceUpdate</code> method. That is: every time we call the <code>AddUserInterfaceUpdate</code> method, the Thread will fire its <code>UserInterfaceUpdate</code> event. Think about this as a <em>bridge</em> between our Thread and the main app thread.</li>
<li>The second approach is the one we use when creating the Thread instances from code. In this case, the solution is simple and is the one we usually use to <em>delegate</em> the code to execute in the Action event of the Timer class. <code>AddHandler</code> sets the method we want to execute in substitution of the <code>UserInterfaceUpdate</code> event handler of a Thread instance. As usual, make sure that the delegated method has the right signature: receiving a Thread object as its first parameter and the data we are interested in as the second parameter.</li>
</ul>
<p><iframe loading="lazy" title="Threads en Xojo 2019R2 y Posterior" width="500" height="375" src="https://www.youtube.com/embed/XHLL5hCQSSo?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></p>
<p>The example project available <a href="https://bit.ly/2Ni156h">here</a>, shows the implementation of both cases, how the Threads sends the data to update the user interface and how such data is received and accessed in the corresponding Thread Event Handler or delegated Method.</p>
<p>As you can see in the example, the user interface is responsive to the user interaction while the two threads do their work.</p>
<p>Easier and faster!</p>
<p><em data-rich-text-format-boundary="true">Javier Rodri­guez has been the Xojo Spanish Evangelist since 2008, he’s also a Developer, Consultant and Trainer who has be using Xojo since 1998. He manages <a href="http://www.aprendexojo.com">AprendeXojo.com</a> and is the developer behind the GuancheMOS plug-in for Xojo Developers, GuancheID, AXControlGrid, AXImageCanvas, Markdown Parser for Xojo, and HTMLColorizer for Xojo among others.</em></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Guest Post: Animating Xojo, Part 4</title>
		<link>https://blog.xojo.com/2019/08/21/guest-post-animating-xojo-part-4/</link>
		
		<dc:creator><![CDATA[Anthony Cyphers]]></dc:creator>
		<pubDate>Wed, 21 Aug 2019 10:00:20 +0000</pubDate>
				<category><![CDATA[Guest Post]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Animation]]></category>
		<category><![CDATA[UI]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=5992</guid>

					<description><![CDATA[In this final part in his 4 part series on Animating Xojo, Anthony Cyphers covers easing, which can make the most drab User Interface interactions beautiful.]]></description>
										<content:encoded><![CDATA[
<p>In <a href="https://blog.xojo.com/2019/07/24/guest-post-historical-methods/">Part 1</a> we covered the history of animating UI effects in Xojo. In <a href="https://blog.xojo.com/2019/07/31/guest-post-animating-xojo-part-2/">Part 2</a> we dug in to linear interpolation. In <a href="https://blog.xojo.com/2019/08/15/guest-post-animating-xojo-part-3/">Part 3</a> saw the addition of support for concurrent animations and color changes. In Part 4 we’ll cover easing, which can make the most drab User Interface interactions beautiful.</p>



<h3 class="wp-block-heading">Easing</h3>



<h4 class="wp-block-heading">What is Easing?</h4>



<p>To quote&nbsp;<a href="https://developers.google.com/web/fundamentals/design-and-ux/animations/the-basics-of-easing">Paul Lewis</a>:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Nothing in nature moves linearly from one point to another. In reality, things tend to accelerate or decelerate as they move. Our brains are wired to expect this kind of motion, so when animating, you should use this to your advantage. Natural motion makes your users feel more comfortable with your apps, which in turn leads to a better overall experience.</p><cite><a href="https://developers.google.com/web/fundamentals/design-and-ux/animations/the-basics-of-easing">https://developers.google.com/web/fundamentals/design-and-ux/animations/the-basics-of-easing</a></cite></blockquote>



<p>Based on that, we can define easing as a more natural-appearing change in value between a start and end point which is designed to make a user feel more comfortable with changes in the user interface.</p>



<h4 class="wp-block-heading">Types of Easing Functions</h4>



<p>Easing functions can be broken down in to three basic types:</p>



<ul class="wp-block-list"><li><code>In</code>&nbsp;— An animation that starts slowly and increases in speed over time</li><li><code>Out</code>&nbsp;— An animation that starts quickly and decreases in speed over time</li><li><code>InOut</code>&nbsp;— A combination of InOut that begins and ends quickly with a slow transition in the middle.</li></ul>



<h4 class="wp-block-heading">What Does Easing Look Like?</h4>



<p>There are a number of currently standard UI easing functions (as seen in CSS, various JavaScript frameworks, and even OS-provided implementations), but one of the more interesting sets is called Elastic. Elastic easing functions simulate the motion you might observe if you stretched out a piece of elastic then released it. You get a dramatic change as the elastic fibers quickly contract, then a slower series of changes as the momentum dissipates. To visualize that in a diagram:</p>



<figure class="wp-block-image"><img decoding="async" src="https://graffitisuite.com/downloads/ms_17332-768x414.png" alt="" class="wp-image-14561"/></figure>



<p>This can be used to provide some really enthralling UI transitions that’ll make both you and your users much happier as it just feels more natural than making Element A of your UI disappear and Element B appear, or using a linear animation to swap the two elements.</p>



<h4 class="wp-block-heading">What Does an Easing Function Look Like</h4>



<p>Easing functions can be incredibly simple, as you saw in our lerp method in Part 2, or as complex as you can imagine. Our example of Elastic easing, while not the most complex, is pretty interesting mathematically (if you’re terrible at math like I am).</p>



<pre class="wp-block-preformatted">Private Function easeInElastic(startValue as Double, endValue as Double, alphaValue as Double) as Double
   Return ((endValue - startValue) * (0.04 * alphaValue / (alphaValue - 1) * Sin( 25 * (alphaValue - 1) ))) + startValue
 End Function</pre>



<p>Basically what this method is doing, and my grasp of the math is admittedly pretty thin, is it’s taking the start and end value and creating a diminishing sine wave to simulate the change over time. I normally would say that this should be broken down in to multiple lines to make it easier to read, possibly by using no fewer than three variables, but we really want it to be quick.</p>



<p>If we did break it down, it would look more like this:</p>



<pre class="wp-block-preformatted">Private Function easeInElastic(startValue as Double, endValue as Double, alphaValue as Double) as Double
   dim changeValue as Double = endValue - startValue
   dim differenceValue as Double = (0.04 * alphaValue / (alphaValue - 1) * Sin( 25 * (alphaValue - 1) ))
   Return (changeValue * differenceValue) + startValue
 End Function</pre>



<p>Which may be easier to read for some of us, but those variable declarations have a cost.</p>



<p>Many of the easing functions you’ll see in this part of the series are adapted for Xojo (with some heavy modification in most places) from&nbsp;<a href="https://github.com/danro/jquery-easing/blob/master/jquery.easing.js">Robert Penner’s Easing Functions</a>&nbsp;(BSD License). There’s a note on the Animated Canvas project item if you wish to explore the sources.</p>



<h4 class="wp-block-heading">What Types of Easing Functions Should I Use?</h4>



<p>UI animations are, typically, something you want to happen fairly quickly. Given that, you likely won’t use&nbsp;<code>InOut</code>&nbsp;easing functions very often as they can feel slower to your end user.</p>



<p><code>In</code>&nbsp;functions can be off putting to users as the natural expectation of seeing the most movement at the end of an animation is antithetical to&nbsp;<code>In</code>&nbsp;functions and may feel slow or confusing for some users.</p>



<p>Based on those theories, you’ll typically employ&nbsp;<code>Out</code>&nbsp;functions in your UI animations, as they’re both quick and easier for our brains to understand in a UI setting. That said, there will be times when other types of easing functions are more suited to an individual task and you must use your best judgement and listen to your QA/users if they complain about it. Animation type and length are a delicate balance.</p>



<h4 class="wp-block-heading">Easing Lengths</h4>



<p>As I alluded to earlier, the timing of your chosen easing function is incredibly important. The following table should be a good starting point for appropriate animation lengths for different types of operations.</p>



<table class="wp-block-table"><tbody><tr><td>Color (In)</td><td>100-250ms</td></tr><tr><td>Color (Out)</td><td>100-250ms</td></tr><tr><td>Color (InOut)</td><td>500-1000ms</td></tr><tr><td>Dimensions/Position (In)</td><td>800-1200ms</td></tr><tr><td>Dimensions/Position (Out)</td><td>800-1200ms</td></tr><tr><td>Dimensions/Position(InOut)</td><td>1500-2500ms</td></tr></tbody></table>



<p>These are the values I typically start with, and alter them based on the responsiveness of the UI and the desired effect. Your mileage may vary.</p>



<h3 class="wp-block-heading">Code Changes</h3>



<p>While I won’t cover the addition of each of the example easing functions that I’ve provided in the example project, I will cover the functional changes to our existing codebase and the addition of the Elastic easing functions.</p>



<h4 class="wp-block-heading">AnimationEasing Property</h4>



<p>Our first step is to create a new property on our AnimatedCanvas class called AnimationEasing. In our demo window we’ll set this value based on selection in a PopupMenu to make it easy to switch between different easing functions and view their output. It’s going to public and computed so we can show it in the Inspector.</p>



<pre class="wp-block-preformatted">Private Property mAnimationEasing as Easings

 Public Property AnimationEasing as Easings
 Get
   Return mAnimationEasing
 End Get

 Set
   mAnimationEasing = value
 End Set

 End Property</pre>



<h4 class="wp-block-heading">Easings Enumeration</h4>



<p>Next we to create an enum for our various easing functions. It’s pretty straight-forward, and we’ll use it to tell our animation controller code what to do in the animation operations we define in our Dictionary objects.</p>



<pre class="wp-block-preformatted">Public Enum Easings
 Linear
 InQuad
 OutQuad
 InOutQuad
 InCubic
 OutCubic
 InOutCubic
 InElastic
 OutElastic
 InOutElastic
 End Enum</pre>



<h4 class="wp-block-heading">Dictionary Definition</h4>



<p>We are, again, modifying our Dictionary object definition. This time we’re passing along the desired easing effect. Our new definition looks like this:</p>



<pre class="wp-block-preformatted">new Dictionary("op" : &lt;OperationToComplete", "l" : &lt;LengthOfAnimation&gt;, "m" : &lt;EasingFunction&gt;, "t" : &lt;StartTime&gt;, "s" : &lt;StartValue&gt;, "e" : &lt;EndValue&gt;)</pre>



<p>You can see that all we’ve really done from Part 3 is add a Key/Value pair for the easing. I assigned this to the “m” key to represent “method of change”, but you could use anything you like here.</p>



<h4 class="wp-block-heading">MouseEnter and MouseExit</h4>



<p>We actually don’t need any changes here for our color animation, as this will continue to use the&nbsp;<code>lerpColor</code>&nbsp;function we previously defined. Color change animations should typically be quick and applying anything but a linear easing to them can both look and feel bad if done improperly, so I won’t cover it here. When in doubt, for color animation, stick with linear and keep it around 100-250ms.</p>



<h4 class="wp-block-heading">MouseUp</h4>



<p>MouseUp, likewise isn’t changing much. We’re basically just adding the easing Key/Value to our existing Dictionary objects like so:</p>



<pre class="wp-block-preformatted">animQueue_Add(new Dictionary("op" : "width", "l" : manimTime, "m" : mAnimationEasing, "t" : Microseconds, "s" : Width, "e" : 
If(isExpandedWidth, 10, expandedWidth)))</pre>



<h4 class="wp-block-heading">doEasing Function</h4>



<p>We need a function to take our&nbsp;<code>Easings</code>&nbsp;enumeration value and perform the specified easing function. In this example I’m using a&nbsp;<code>Select Case</code>&nbsp;block, but I’ve also implemented a nice jump table using delegates in other projects.</p>



<pre class="wp-block-preformatted">Private Function doEasing(easing as Easings, startValue as Double, endValue as Double, alphaValue as Double) as Double
   select case easing
   case easings.Linear
     Return lerp( startValue, endValue, alphaValue )
   case easings.InQuad
     Return easeInQuad( startValue, endValue, alphaValue )
   case easings.OutQuad
     Return easeOutQuad( startValue, endValue, alphaValue )
   case easings.InOutQuad
     Return easeInOutQuad( startValue, endValue, alphaValue )
   case easings.InCubic
     Return easeInCubic( startValue, endValue, alphaValue )
   case easings.OutCubic
     Return easeInOutCubic( startValue, endValue, alphaValue )
   case easings.InOutCubic
     Return easeInOutCubic( startValue, endValue, alphaValue )
   case easings.InElastic
     Return easeInElastic( startValue, endValue, alphaValue )
   case easings.OutElastic
     Return easeOutElastic( startValue, endValue, alphaValue )
   case easings.InOutElastic
     Return easeInOutElastic( startValue, endValue, alphaValue )
   end select
 End Function</pre>



<p>As you can see, it takes the easing parameter representing the desired function, and the values we need to animate, passes all of that along to the requested easing function, and returns the value. A call to this method will replace our previous call to&nbsp;<code>lerp</code>&nbsp;in our Timer’s Action event handler.</p>



<h4 class="wp-block-heading">Our Easing Functions</h4>



<p>As I said earlier, I won’t cover all of the functions in the article, but I will include the Elastic functions here for your perusal. To see all of the easing functions included, be sure to download the example project at the end of the article.</p>



<pre class="wp-block-preformatted">Private Function easeInElastic(startValue as Double, endValue as Double, alphaValue as Double) as Double
   Return ((endValue - startValue) * (0.04 * alphaValue / (alphaValue - 1) * Sin( 25 * (alphaValue - 1) ))) + startValue
 End Function

 Private Function easeOutElastic(startValue as Double, endValue as Double, alphaValue as Double) as Double
   Return ((endValue - startValue) * ((0.04 - 0.04 / alphaValue) * Sin( 25 * alphaValue ) + 1)) + startValue
 End Function

 Private Function easeInOutElastic(startValue as Double, endValue as Double, alphaValue as Double) as Double
   dim opChange as Double = Abs(endValue - startValue)

 if alphaValue &lt;= 0.5 then
     return easeInElastic(startValue, opChange /  2, alphaValue * 2)
   else
     return easeOutElastic(opChange / 2, endValue, Abs(1 - (alphaValue * 2)))
   end if
 End Function</pre>



<p>We’ve already discussed purpose and expectation for&nbsp;<code>In</code>/<code>Out</code>, but take a look at&nbsp;<code>easeInOutElastic</code>. We accomplish this effect by splitting the run-time of the animation into two distinct parts and executing the appropriate easing function based on where we are in the animation.&nbsp;<code>In</code>&nbsp;happens at &lt;= 50% of our total animation time, and&nbsp;<code>Out</code>happens at &gt; 50% of our animation time. This gives us a nice, seamless transition in our&nbsp;<code>InOut</code>&nbsp;animation as the value at 50% should be close — if not identical — in both easing functions.</p>



<h4 class="wp-block-heading">animTimer_Action</h4>



<p>Our changes in animTimer_Action are also pretty minimal. Since we’re not applying one of the more advanced easing functions to our previously discussed color animation, I’ll only cover the changes we’re making to the Width and Height operations.</p>



<p>First, we need to add a new variable declaration to the top of our method. This is where we’ll store the easing type.</p>



<pre class="wp-block-preformatted">Dim animOpEasing As Easings</pre>



<p>Then, after our&nbsp;<code>Else</code>&nbsp;at line 87, where we get our values from the current&nbsp;<code>animOp</code>&nbsp;Dictionary, we will assign the current operation’s easing (or “m” key) value to our new variable.</p>



<pre class="wp-block-preformatted">animOpEasing = animOp.Value("m")</pre>



<p>Now that we know which easing function we want to apply to the current operation, and we’ve already defined our&nbsp;<code>doEasing</code>&nbsp;function, all we need to do is swap out our line (line 100) that previously used the&nbsp;<code>lerp</code>&nbsp;function to assign the appropriate value to&nbsp;<code>animStepDouble</code>, to use our new&nbsp;<code>doEasing</code>&nbsp;function.</p>



<pre class="wp-block-preformatted">animStepDouble = doEasing(animOpEasing, animStartDouble, animEndDouble, timePercent)</pre>



<h3 class="wp-block-heading">Series Finale</h3>



<p>I do hope that, throughout this series, you’ve learned a little something about how and when to implement animation in user interfaces, some decent practices for doing so in an encapsulated way, and maybe picked up a few other pointers.</p>



<p>I had a lot of fun writing this and interacting with readers who reached out with questions and suggestions, and I hope to do more guest posts on the Xojo blog in the future. I’d like to thank Team Xojo not only for their great product and support, but also for allowing me to stand at their podium for a short time and share with you all.</p>



<p>If you would like to see more easing functions, or how I’ve implemented a full animation controller and the delegate jump table, GraffitiAnimator will soon be coming to GraffitiSuite Desktop Edition, and can be acquired&nbsp;<a href="https://graffitisuite.com/">directly</a>, via the&nbsp;<a href="https://www.xojo.com/store/?utm_content=1565880397&amp;utm_medium=social&amp;utm_source=twitter#addons">Xojo Extras store</a>, or for a limited time as part of the&nbsp;<a href="http://omegabundle.net/">Omega Bundle</a>.</p>



<p>Finally, you can download the example project for Part 4&nbsp;<a href="https://graffitisuite.com/downloads/ms_17333.zip">here</a>.</p>



<p>Thank you all for following along with me!</p>



<p><em>Anthony G. Cyphers is the Lead Developer and Sole Proprietor of&nbsp;</em><a rel="noreferrer noopener" href="https://graffitisuite.com/" target="_blank"><em>GraffitiSuite Solutions</em></a><em>, and has been providing custom Xojo components and contract development since 2003. He runs the&nbsp;</em><a rel="noreferrer noopener" href="https://t.co/WQSD3O2V6R" target="_blank"><em>Xojo User’s Discord server</em></a><em>, and is an administrator in the&nbsp;</em><a rel="noreferrer noopener" href="https://www.facebook.com/groups/xojo.dev/" target="_blank"><em>Xojo User’s Facebook user group</em></a><em>.</em></p>



<figure class="wp-block-image is-resized"><img loading="lazy" decoding="async" src="https://blog.xojo.com/wp-content/uploads/2019/07/AnthonyAndLaura_Small.png" alt="" class="wp-image-5959" width="131" height="133" srcset="https://blog.xojo.com/wp-content/uploads/2019/07/AnthonyAndLaura_Small.png 375w, https://blog.xojo.com/wp-content/uploads/2019/07/AnthonyAndLaura_Small-296x300.png 296w" sizes="auto, (max-width: 131px) 100vw, 131px" /></figure>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Guest Post: Animating Xojo, Part 3</title>
		<link>https://blog.xojo.com/2019/08/15/guest-post-animating-xojo-part-3/</link>
		
		<dc:creator><![CDATA[Anthony Cyphers]]></dc:creator>
		<pubDate>Thu, 15 Aug 2019 10:00:56 +0000</pubDate>
				<category><![CDATA[Guest Post]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Animation]]></category>
		<category><![CDATA[UI]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=5964</guid>

					<description><![CDATA[In Part 1 we covered the basic history of animating in Xojo using pre-calculated chunks to modify the width of our component. In Part 2&#8230;]]></description>
										<content:encoded><![CDATA[
<p>In <a href="https://blog.xojo.com/2019/07/24/guest-post-historical-methods/">Part 1</a> we covered the basic history of animating in Xojo using pre-calculated chunks to modify the width of our component. In <a href="https://blog.xojo.com/2019/07/31/guest-post-animating-xojo-part-2/">Part 2</a> we went a bit further by using linear interpolation (lerp) to calculate our current width at each step of the animation process, and setup for concurrent animation.</p>



<p>In this part we’ll be covering a few different things, chiefly concurrent animations. But that’s not all, as I’ve added a lerpColor function to show you how to animate color changes.</p>



<h3 class="wp-block-heading">Concurrent Animations</h3>



<p>Using self-contained concurrent animations in a UI class is an interesting exercise. You need to have the basic setup for an animation controller complete with a method of adding animation operations to a queue and removing completed animations. Typically, however, if you were building out animations on an application scale, you’d build a class that acted as the animation controller and may raise events for updating the elements as the animation progresses. In this example we’ll just build them straight in to our component because we want this to be entirely independent of the rest of the application architecture.</p>



<p>As this part focuses on concurrent animations, we’re not implementing a keyframe methodology for queuing. We’re using the queue purely to have multiple animations running together.</p>



<h4 class="wp-block-heading">Defining The Queue</h4>



<p>In Part 2 we added the following property to AnimatedCanvas:</p>



<pre class="wp-block-preformatted">animQueue As Dictionary</pre>



<p>For this part, we’re going to make a slight modification to that property definition so that it will support multiple animation operations. We’re just going to turn it into an array:</p>



<pre class="wp-block-preformatted">animQueue() As Dictionary</pre>



<h4 class="wp-block-heading">Dictionary Changes</h4>



<p>If you remember from last time we used the following definition for our Dictionary objects:</p>



<ul class="wp-block-list"><li>Start Time</li><li>Start Width</li><li>End Width</li></ul>



<p>In this part we’re going to further leverage Dictionary’s use of Variant to expand our functionality. While we previously used the following Dictionary structure for our operations:</p>



<pre class="wp-block-preformatted">Dictionary("s" : &lt;StartTimeInMicroseconds&gt;, "sw" :&lt;StartWidth&gt; , "ew" : &lt;EndWidth&gt;)</pre>



<p>We’re now defining our animOp Dictionaries as:</p>



<pre class="wp-block-preformatted">Dictionary("op" : &lt;OperationToAnimate&gt;, "l" : &lt;AnimationLength&gt;, "t" : &lt;StartTimeInMicroseconds&gt;, "s" &lt;StartValue&gt;: , "e" : &lt;EndValue&gt;, "o" : &lt;OptionalOlderAnimationOp&gt;)</pre>



<p>This allows us to create an animation operation for practically anything we can think of as long as we properly code for it in our animation Timer’s Action event handler method, and give it any length we desire rather than a common time for all operations.</p>



<h4 class="wp-block-heading">Adding to the Queue</h4>



<p>We’re going to add a new method to our AnimatedCanvas class called&nbsp;<code>animQueue_Add</code>&nbsp;that takes&nbsp;<code>animOp As Dictionary</code>&nbsp;for its sole parameter. This method will act as a basic out-of-the-loop controller when an animation is to be triggered and determine if this is a new animation operation or one that is already currently in the queue.</p>



<p>In this example I’ve setup for both a Cancel/Start type animation operation (which completely cancels the previous animation and begins a new one with the full animation time), and Continue type animation operation that preserves the original animation time within the new animation time, which is explained in more depth later.</p>



<pre class="wp-block-preformatted">Private Sub animQueue_Add(animOp as Dictionary)
   '// This method is part of our animation controller.
   '   It appends to or modifies our animation queue,
   '   which runs concurrent rather than consecutive
   '   operations.
   '   We first check to make sure that the new animation
   '   operation dictionary isn't nil.
   if IsNull(animOp) then Return

 '// We need to find out if we already have an operation
   '   in the queue for this, so we're going to store our
   '   index in a variable, which we'll get from our new
   '   anim_IndexOf method.
   dim foundIndex as Integer = animQueue_IndexOf(animOp.Value("op"))

 '// If the operation exists, overwrite it. Otherwise,
   '   append it to our queue so that the timer will
   '   pick it up on its next Action.
   if foundIndex &gt;= 0 then

 <code>'// We're also going to implement what I call Time </code>
 <code>'   Preservation. I'm sure there another name that</code>
<code> '   this is more commonly referred to as, but I</code>
<code> '   just don't know it. When PreserveTimes = True</code>
<code> '   then the animation operation overwrite will</code>
<code> '   only use the remaining time of the oldest</code>
<code> '   overriden animation operation. </code>
 <code>if mPreserveTimes then</code>

<code>   '// Grab the oldest op in our override chain so</code>
<code>   '   we can perform the math necessary to calculate</code>
<code>   '   an appropriate time remainder.</code>
<code>   dim oldOp as Dictionary = animQueue_OldestOp(animQueue(foundIndex))</code>

<code>   if not IsNull( oldOp ) then</code>
<code>     '// Set our animation length to the remaining value.</code>
<code>     '   We're getting the assigned length of the animation</code>
<code>     '   and subtracted the difference between our two</code>
<code>     '   operation start times.</code>
<code>     animOp.Value("l") = animOp.Value("l") - ((animOp.Value("t").DoubleValue - oldOp.Value("t").DoubleValue) / 1000)</code>

<code>     '// Set oldOp to our "o" key in case of future overrides.</code>
<code>     animOp.Value("o") = oldOp</code>
<code>   end if</code>
<code> end if </code>

<code>'// Overwrite the operation.</code>
<code> animQueue(foundIndex) = animOp</code>
 else

 <code>'// Add the operation to the queue.</code>
<code> animQueue.Append(animOp)</code>
 end if

 '// Make sure that our animation timer is enabled.
   animTimer.Mode = 2
 End Sub</pre>



<p>As you can see, it’s not an incredibly complex method. We’re just checking our&nbsp;<code>animQueue</code>&nbsp;property to see an animation currently exists for this operation. If we find it, we replace it. If we don’t, we just add it to the tail-end of the queue. The final line, as in the previous version, kicks off our animation timer.</p>



<h4 class="wp-block-heading">Checking Our Queue</h4>



<p>The next new method we’re going to add is our method to check if the animation operation already exists in our queue. It’s a straightforward method where we compare the “op” value of items in the queue to a specified “op” value. If an operation exists for that action, we return the index within the queue, otherwise return -1.</p>



<pre class="wp-block-preformatted">Private Function animQueue_IndexOf(op as String) as Integer
   '// This method will check our queue for the
   '   operation specified in the "op" parameter.
   '   If it exists, we'll return the index. Otherwise
   '   we return -1 to denote that this is a new op.

 '// We're creating our variable before hand so
   '   we're not doing it in each iteration of the
   '   loop, which could slow things down a bit.
   dim currDict as Dictionary

 '// Likewise, we're creating a variable to store
   '   the maximum index of our animQueue array. If
   '   we did this, instead, in the For statement,
   '   the value would be recalculated each time
   '   unless something changed that I don't know about.
   dim intMax as Integer = animQueue.Ubound

 '// We're starting from the end, just in case
   '   the contents of the queue change in the middle,
   '   we're less likely to hit an exception.
   for intCycle as Integer = intMax DownTo 0
     '// We're still going to add exception handling
     '   just in case.
     Try
       currDict = animQueue(intCycle)
     Catch e as OutOfBoundsException
       Continue
     End Try

 <code>'// If our current dictionary's "op" value</code>
<code> '   matches the "op" value we're searching for</code>
<code> '   then we'll return the index. if currDict.Value("op") = op then</code>
<code>   Return intCycle</code>
<code> end if</code>
 next

 '// No matching operation found, so we return -1.
   Return -1
 End Function</pre>



<h3 class="wp-block-heading">Time Preservation</h3>



<p>One new feature we’re implementing is what I call animation time preservation. This shortens subsequent animations of the same operation to honor the original time until one of them is able to complete.</p>



<h4 class="wp-block-heading">PreserveTimes property</h4>



<p>For our animation time preservation, we’re adding a property to the class so we can turn this on and off at will. We’ll make it public and computed so we can add it to the inspector.</p>



<pre class="wp-block-preformatted">Private Property mPreserveTimes as Boolean = True

 Public Property PreserveTimes as Boolean
   Get
     Return mPreserveTimes
   End Get
   Set
     mPreserveTimes = value
   End Set
 End Property</pre>



<h4 class="wp-block-heading">Getting the Oldest Op</h4>



<p>This all really relies on one method,&nbsp;<code>animQueue_OldestOp</code>&nbsp;which checks the “o” key of the specified animation operation to see if an older operation already exists. If it does, we’ll return it, otherwise return the operation passed in to the method. If you take a look at the changes to&nbsp;<code>animQueue_Add</code>&nbsp;above, you’ll see how we use this.</p>



<pre class="wp-block-preformatted">'// In this method we're just checking to see if
 '   there was a pre-existing operation when this
 '   one was created so that we can use its start
 '   time to shorten our new animation time.

 if IsNull(animOp) then Return Nil

 if animOp.HasKey("o") then
   dim oldOp as Dictionary = animOp.Value("o")
   Return oldOp
 end if

 Return animOp</pre>



<h3 class="wp-block-heading">Expanding the Height</h3>



<p>For this example, to highlight multiple concurrent animations, I’ve also added the ability to animate the height in addition to the width. We’re basically just duplicating the existing properties for our width animation, but applying the values to height. This could be modified to use a&nbsp;<code>Point</code>&nbsp;or&nbsp;<code>Rect</code>&nbsp;to achieve the same effect, but this implementation is better for showing how the modifications we’ll be making to the animation Timer’s action actually work by breaking it down independently.</p>



<h4 class="wp-block-heading">Properties</h4>



<p>As with our Width animation, we need to track what our target expanded Height should be as well as the current state of that dimension. For Width we have an&nbsp;<code>expandedWidth</code>&nbsp;property, so we’ll add an&nbsp;<code>expandedHeight</code>&nbsp;property to match.</p>



<pre class="wp-block-preformatted">Private Property expandedHeight as Integer</pre>



<p>In this version, we’re also renaming our old&nbsp;<code>expanded</code>&nbsp;property to&nbsp;<code>isExpandedWidth</code>:</p>



<pre class="wp-block-preformatted">Private Property isExpandedWidth as Boolean = True</pre>



<p>And adding a new corresponding property for Height:</p>



<pre class="wp-block-preformatted">Private Property isExpandedHeight as Boolean = True</pre>



<p>Finally, we need a property that keeps track of whether we’re currently animating our dimensions so that our subsequent clicks during a color-only animation properly toggle our&nbsp;<code>isExpanded*</code>&nbsp;properties. We could do this by searching the&nbsp;<code>animOp</code>&nbsp;array, but just storing it is probably a bit quicker.</p>



<pre class="wp-block-preformatted">Private Property isAnimatingDimensions as Boolean</pre>



<p>There are better ways to implement tacking of these states, but for this example I want the verbosity.</p>



<h3 class="wp-block-heading">MouseUp Changes</h3>



<p>Since we’re now animating both Width and Height and implementing our rudimentary animation controller, we need to make some changes to our MouseUp event handler. Primarily we’re duplicating what we already do for Width to account for our new Height animation, and applying the changes to the properties we’ve already discussed. We check to see if we’re currently animating Width or Height before toggling their values to avoid issues in the animation timer’s Action handler.</p>



<pre class="wp-block-preformatted">Sub MouseUp(X As Integer, Y As Integer) Handles MouseUp
   '// Just in case we hit some strange scenario where
   '   the timer is disposed of. Should, theoretically,
   '   never happen in this case, but better safe than sorry.
   if IsNull(animTimer) then Return

 '// Now we're going to check for a currently running
   '   animation. If an animation operation of this type is
   '   already underway, all we need to do
   '   is switch the direction the animation is running.
   '   In a full animation controller, this would be handled
   '   internally by chaining or cancelling, most likely,
   '   but this works for our purposes.
   if animQueue_IndexOf("width") &gt;= 0 then
     isExpandedWidth = not isExpandedWidth
   end if
   if animQueue_IndexOf("height") &gt;= 0 then
     isExpandedHeight = not isExpandedHeight
   end if

 '// Here we create our dictionary objects containing
   '   everything our Timer's action event needs to do
   '   the work. The current time in Microseconds, which
   '   will be our start time, the start value, and the
   '   expected result value. This "10" is hard-coded
   '   just so that we can actually click on the canvas
   '   again to reverse the animation if it is fully
   '   collapsed. In most scenarios you wouldn't have
   '   a hard-coded value like this and you may even be
   '   triggering the animation from a different element
   '   altogether, so this value is purely for demonstration
   '   purposes in this project.
   '   animQueue_Add is a new method in this part of the
   '   series, and acts as an animation controller.
   animQueue_Add(new Dictionary("op" : "width", "l" : manimTime, "t" : Microseconds, "s" : Width, "e" : If(isExpandedWidth, 10, expandedWidth)))
   animQueue_Add(new Dictionary("op" : "height", "l" : manimTime, "t" : Microseconds, "s" : Height, "e" : If(isExpandedHeight, 10, expandedHeight)))
 
'// Finally, enable the timer to perform the animation.
   animTimer.Mode = 2
 
'// We've added this event, just in case there's
   '   something you want to trigger at the start of the
   '   animation.
   RaiseEvent BeforeAnimate
 End Sub</pre>



<h3 class="wp-block-heading">The New lerpColor</h3>



<p>For Part 3, I wanted to add a little something extra before we roll in to Part 4, just to show how we can use linear interpolation for animating any number of different properties of our AnimatedCanvas class. That means we’re going to animate the background color of our class as well!</p>



<h4 class="wp-block-heading">New Properties</h4>



<p>To support our color animation in this specific example, we need a couple of new properties. These properties give us our start and end points for our color animation, and we’re going to add them to the inspector so that they can be changed when editing a Window or ContainerControl view.</p>



<ul class="wp-block-list"><li>BackgroundColor represents our default background color, which I’ve set to default as red.</li><li>BackgroundColorHover represents the color we want to see when the mouse is over the control, which defaults to blue.</li><li>currentBackgroundColor represents the background color we want to actually apply, and is changed during the animation process.</li></ul>



<pre class="wp-block-preformatted">Public Property BackgroundColor as Color
   Get
     Return mBackgroundColor
   End Get
   Set
     mBackgroundColor = value
   End Set
 End Property
 Public Property BackgroundColorHover as Color
   Get
     Return mBackgroundColorHover
   End Get
   Set
     mBackgroundColorHover = value
   End Set
 End Property

 Private Property mBackgroundColor as Color = &amp;cff0000
 Private Property mBackgroundColorHover as Color = &amp;c0000ff
 Private Property currentBackgroundColor as Color = &amp;cff0000</pre>



<h4 class="wp-block-heading">The Paint Event</h4>



<p>Our Paint event only needs one small modification to account for the changes we’re making. We previously used a static red color&nbsp;<code>&amp;cff0000</code>&nbsp;but we need to switch to using the&nbsp;<code>currentBackgroundColor</code>&nbsp;property to support the animation.</p>



<pre class="wp-block-preformatted">Sub Paint(g As Graphics, areas() As REALbasic.Rect) Handles Paint
   '// Fill the canvas with our current color.
   g.ForeColor = currentBackgroundColor
   g.FillRect(0, 0, g.Width, g.Height)
 End Sub</pre>



<h4 class="wp-block-heading">The MouseEnter Event</h4>



<p>Our first step in animating the color for this example is to implement the MouseEnter event within our class. We’re simply creating a new Dictionary for the animation operation, populating that with our values to be used in the animation timer, then calling&nbsp;<code>animQueue_Add</code>.</p>



<pre class="wp-block-preformatted">Sub MouseEnter() Handles MouseEnter
   '// In this version, we're going to animate color change
   '   based on whether the mouse is over the control.
   '   So in MouseEnter we start animating from our
   '   currentBackgroundColor to our BackgroundColorHover.
   if me.Enabled then
     animQueue_Add(new Dictionary("op" : "color", "l" : 250, "t" : Microseconds, "s" : currentBackgroundColor, "e" : mBackgroundColorHover))
   end if
 End Sub</pre>



<p>You’ll notice that, without the comments, this entire event handler is very short. Part of the goal as I build this functionality is always to make it as easy to implement as possible as I’ll likely use it in a number of different ways for each UI component. Sometimes I have the Dictionary values as parameters of the&nbsp;<code>animQueue_Add</code>&nbsp;method, but I want to show this in this way for this example.</p>



<p>If I’m implementing animation on an application-wide scale, I’ll typically use a custom class called&nbsp;<code>AnimationOperation</code>, with the values for the operation stored as properties and passed via the&nbsp;<code>Constructor</code>method, then a call to add the resulting class instance to the queue for the&nbsp;<code>AnimationController</code>.</p>



<p>We also assign a static 250ms to color change animations, just to test our dynamic animation times, but you may typically want color change animations to be quicker than other animations in your application just so they stand out less.</p>



<h4 class="wp-block-heading">The MouseExit Event</h4>



<p>MouseExit, like MouseEnter, just creates and adds an animation operation dictionary with the values we want to use. In this case, we want to revert the color back to the default background color.</p>



<pre class="wp-block-preformatted">Sub MouseExit() Handles MouseExit
   '// In this version, we're going to animate color change
   '   based on whether the mouse is over the control.
   '   So in MouseExit we start animating from our
   '   currentBackgroundColor to our default BackgroundColor.
   if me.Enabled then
     animQueue_Add(new Dictionary("op" : "color", "l" : 250, "t" : Microseconds, "s" : currentBackgroundColor, "e" : mBackgroundColor))
   end if
 End Sub</pre>



<h4 class="wp-block-heading">The lerpColor Method</h4>



<p>Now that we have our class setup out of the way, we can create our&nbsp;<code>lerpColor</code>&nbsp;method. In this example I’m simply applying linear interpolation to the Red, Green, and Blue values of the passed colors, but you could use any other subset of color properties that you want for your desired effect.</p>



<pre class="wp-block-preformatted">Private Function lerpColor(startColor as Color, endColor as Color, alphaValue as Double) as Color
   '// This method takes starting and ending color values
   '   and applies the lerp method for linear interpolation to
   '   the constituent Red, Green and Blue values to generate
   '   the new color value based on the animation's elapsed
   '   time.
   '   This could be switched from RGB for different effects,
   '   or you could just use Color.Alpha for making objects
   '   fade in or out.
   dim animStepR as Double = Lerp(startColor.Red, endColor.Red, alphaValue)
   dim animStepG as Double = Lerp(startColor.Green, endColor.Green, alphaValue)
   dim animStepB as Double = Lerp(startColor.Blue, endColor.Blue, alphaValue)

   Return RGB(animStepR, animStepG, animStepB)
 End Function</pre>



<h3 class="wp-block-heading">The Timer Action Handler</h3>



<p>This is where we’re making the most changes in a single method. Not only are we implementing the animation controller methodology, but we’re also adding two new animation operations — height and color, in addition to the original width — so a lot of this will look different from Parts 1 &amp; 2 in this series.</p>



<pre class="wp-block-preformatted">Private Sub animTimer_Action(sender as Timer)
   '// We're going to declare all of our variables outside of the
   '   loop so that we're not using precious time and resources
   '   in every iteration of the loop doing it.
   dim animOp as Dictionary
   dim animOpType as String
   dim animStepDouble as Double
   dim animStepColor as Color
   dim animStartTime, timePercent, animLength as Double
   dim animStartDouble, animEndDouble as Double
   dim animStartColor, animEndColor, newColor as Color

 '// Declare our loop maximum variable. Historically each
 '   iteration of the loop was known to traverse the array
 '   to get the maximum value if this wasn't stored in advance.
 '   I haven't tested this myself recently.
 dim intMax as Integer = animQueue.Ubound

 '// We start at Ubound and traverse the array in reverse because
 '   we'll be removing animations from the queue as they complete,
 '   and this is the best way to avoid OutOfBoundsExceptions.
 for intCycle as Integer = animQueue.Ubound DownTo 0

 <code>'// Get our current operation dictionary from the queue. </code>
 <code>animOp = animQueue(intCycle) </code>

<code>'// Our first step is to make sure we actually have an animation </code>
<code>'   to perform. </code>
<code>if IsNull(animOp) then   </code>
  <code>'// For whatever reason, this entry has been cleared. We'll   </code>
  <code>'   just remove it and continue with the next operation.  </code>
<code>  animQueue.Remove(intCycle)   </code>
  <code>Continue </code>
<code>end if </code>

<code>'// Now we'll get our operation values from the dictionary object. </code>
<code>'   it is possible to run into KeyNotFoundExceptions here, since </code>
<code>'   we're not checking first, but if you do, then you've likely </code>
<code>'   made an error when modifying the code. No animQueue Dictionary </code>
<code>'   should be created without the same set of values since we're </code>
<code>'   making use of variant for the values dependiong on the "op" </code>
<code>'   kay's value. </code>
<code>animOpType = animOp.Value("op").StringValue </code>
<code>animStartTime = animOp.Value("t").DoubleValue </code>
<code>animLength = animOp.Value("l").DoubleValue </code>

<code>'// timePercent is used in the lerp function and gives us a basis </code>
<code>'   for dividing up the distance we need to cover in to constituent </code>
<code>'   pieces for animating. We also use this for cutting out of the </code>
<code>'   animation at the appropriate time. This value ranges from </code>
<code>'   0 to 1.0. We subtract our start time from the current time in </code>
<code>'   microseconds, then divide by one thousand to convert that in to </code>
<code>'   milliseconds. We then divide the result of that by our AnimationTime </code>
<code>'   as that's already expressed in milliseconds. </code>
<code>timePercent = (((Microseconds - animStartTime) / 1000) / animLength) </code>

<code>'// In this part of the series, I show how to animate color changes </code>
<code>'   as well as dimensions. This method uses RGB, but you could </code>
<code>'   alter lerpColor to use any other method you wish. </code>
<code>if animOpType = "color" then   </code>
   <code>'// Get our animation start and end values.   </code>
   <code>animStartColor = animOp.Value("s").ColorValue   </code>
   <code>animEndColor = animOp.Value("e").ColorValue   </code>

   <code>'// Now we're going to pass the necessary parameters in to   </code>
   <code>'   our new lerpColor function to get the current expected   </code>
   <code>'   color at this stage of the animation.   </code>
   <code>animStepColor = lerpColor(animStartColor, animEndColor, timePercent)   </code>

   <code>'// Check to see if this animation operation is complete.   </code>
   <code>'   If so, we remove the operation from the queue and   </code>
   <code>'   move on.   </code>
   <code>if animStepColor = animEndColor or timePercent &gt;= 1 then      </code>
     <code>currentBackgroundColor = animEndColor     </code>
     <code>animQueue.Remove(intCycle)     </code>
     <code>Continue   </code>
    <code>end if   </code>

    <code>'// Assign our lerped color value to the currentBackgroundColor property.     </code>
    <code>currentBackgroundColor = animStepColor   </code>

    <code>'// Since we've now moved our color animation to a place where it   </code>
    <code>'   can be animated without changing the dimensions of the control   </code>
    <code>'   we need to tell the control to update when we set a new color value.</code>
    <code>Invalidate(False) </code>

  <code>else   </code>
    <code>'// Get our animation start and end values.</code>
    <code>animStartDouble = animOp.Value("s").DoubleValue   </code>
    <code>animEndDouble = animOp.Value("e").DoubleValue   </code>

    <code>'// Here we pass our start value, end value, and the percentage   </code>
    <code>'   of time passed to our lerp function parameters to   </code>
    <code>'   calculate what the current width should be at this point   </code>
    <code>'   in the total animation time. Note that, in our previous   </code>
    <code>'   version, we used a step value and modified our current width   </code>
    <code>'   but in this version our step value is the entire calculated   </code>
    <code>'   current width.   </code>
    <code>animStepDouble = Lerp(animStartDouble, animEndDouble, timePercent)   </code>

    <code>'// If we've reached our ending width or our alotted time has   </code>
    <code>'   passed then we bail and set the values we expect at the   </code>
    <code>'   end of the animation.   </code>
    <code>select case animOpType   </code>
    <code>case "width"     </code>

      <code>'// Check to see if this animation operation is complete.     </code>
      <code>'   If so, we remove the operation from the queue and     </code>
      <code>'   move on.     </code>
      <code>if animStepDouble = animEndDouble or timePercent &gt;= 1 then       </code>
        <code>me.Width = animEndDouble ' Set our width to the end result.</code>
        <code>isExpandedWidth = not isExpandedWidth ' Toggle the state boolean.     </code>
        <code>animQueue.Remove(intCycle)       </code>
        <code>Continue     </code>
       <code>end if     </code>

      <code>'// Apply our new width value.     </code>
      <code>me.Width = animStepDouble   </code>

 <code>case "height"     </code>

    <code>'// Check to see if this animation operation is complete.     </code>
    <code>'   If so, we remove the operation from the queue and     </code>
    <code>'   move on.     </code>
    <code>if animStepDouble = animEndDouble or timePercent &gt;= 1 then       </code>
    <code>me.Height = animEndDouble       </code>
    <code>isExpandedHeight = not isExpandedHeight  </code>
<code>    animQueue.Remove(animQueue.IndexOf(animOp))       </code>
    <code>Continue     </code>
  <code>end if     </code>

   <code>'// Apply our new height value.     </code>
   <code>me.Height = animStepDouble   </code>

   <code>end select </code>
  <code>end if</code>
 next

 '// At this stage, we want to see if there are any animation operations
 '   that have yet to complete. If everything is done, then we disable
 '   our timer.
 if animQueue.Ubound &lt; 0 then
    sender.Mode = 0
   end if
 End Sub</pre>



<p>You can see from the code that we’ve moved all of our variable declarations to the top of the method. We do this so that we’re not slowing things down inside the loop by disposing of and redeclaring variables that may be used multiple times. In Part 4 we’ll be adding Pragmas all over the place to make sure our code is even more speedy.</p>



<p>Inside the loop we fill our&nbsp;<code>animOp</code>&nbsp;property with the current animation operation and verify that it isn’t Nil. If animOp is Nil, then we need to go ahead and remove it from the queue.</p>



<p>Next we populate our&nbsp;<code>animOpType</code>,&nbsp;<code>animStartTime</code>, and&nbsp;<code>animLength</code>&nbsp;variables with their corresponding values, and calculate our current&nbsp;<code>timePercent</code>&nbsp;for our lerp functions.</p>



<p>The next block is where all of the magic happens. You can see that we’ve just used the same basic methodology from Part 2, but extended it to support animating color and height in addition to width.</p>



<p>One important thing to note is that we’re calling&nbsp;<code>Invalidate(False)</code>&nbsp;at the end of our conditional if the current operation is a color operation. Without this, our color property’s value would be animated, but the UI would not update to reflect that if this were the only operation currently underway as changes to both Width and Height automatically invalidate the control.</p>



<p>We also do a bit of work on our queue when an animation is complete by removing the current operation when it is complete, and instead of checking the&nbsp;<code>animQueue</code>&nbsp;property for Nil at the end of the method as we did in Part 2, we now check if there are any remaining operations and halt the timer if the queue is empty.</p>



<h3 class="wp-block-heading">Final Thoughts</h3>



<p>While this method may not be best for every situation or every coding style, I’ve found it to be versatile and dependable. This minimal animation controller is surprisingly robust.</p>



<p>As I mentioned earlier, this animation controller does not make use of keyframes for chaining animations. This could be implemented fairly easily, and while I have done it for a number of projects in the past, I won’t be covering that in this series as you should have some idea of how to incorporate that if you so desire.</p>



<p>In the next part I plan to cover&nbsp;<a href="https://developers.google.com/web/fundamentals/design-and-ux/animations/the-basics-of-easing">easing</a>&nbsp;to some degree which, like lerp, controls the speed and change in our animation and can add a massive amount of appeal to your user interface.</p>



<p>You can download the example project for Part 3&nbsp;<a href="https://graffitisuite.com/downloads/ms_17272.zip">here</a>.</p>



<p><em>Anthony G. Cyphers is the Lead Developer and Sole Proprietor of&nbsp;</em><a rel="noreferrer noopener" href="https://graffitisuite.com/" target="_blank"><em>GraffitiSuite Solutions</em></a><em>, and has been providing custom Xojo components and contract development since 2003. He runs the&nbsp;</em><a rel="noreferrer noopener" href="https://t.co/WQSD3O2V6R" target="_blank"><em>Xojo User’s Discord server</em></a><em>, and is an administrator in the&nbsp;</em><a rel="noreferrer noopener" href="https://www.facebook.com/groups/xojo.dev/" target="_blank"><em>Xojo User’s Facebook user group</em></a><em>.</em></p>



<figure class="wp-block-image is-resized"><img loading="lazy" decoding="async" src="https://blog.xojo.com/wp-content/uploads/2019/07/AnthonyAndLaura_Small.png" alt="" class="wp-image-5959" width="128" height="130" srcset="https://blog.xojo.com/wp-content/uploads/2019/07/AnthonyAndLaura_Small.png 375w, https://blog.xojo.com/wp-content/uploads/2019/07/AnthonyAndLaura_Small-296x300.png 296w" sizes="auto, (max-width: 128px) 100vw, 128px" /></figure>



<p></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Guest Post: Animating Xojo, Part 2</title>
		<link>https://blog.xojo.com/2019/07/31/guest-post-animating-xojo-part-2/</link>
		
		<dc:creator><![CDATA[Anthony Cyphers]]></dc:creator>
		<pubDate>Wed, 31 Jul 2019 10:00:16 +0000</pubDate>
				<category><![CDATA[Guest Post]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Animation]]></category>
		<category><![CDATA[UI]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=5950</guid>

					<description><![CDATA[Continuing with what we previously learned in Animating Xojo, Part 1, this version introduces the use of linear interpolation to calculate the current stage of the animation at each step, plus switching to a Dictionary object for variable storage to setup for future parts in this series.]]></description>
										<content:encoded><![CDATA[
<p>Continuing with what we previously learned in <a href="https://blog.xojo.com/2019/07/24/guest-post-historical-methods/">Animating Xojo, Part 1</a>, this version introduces the use of linear interpolation to calculate the current stage of the animation at each step, plus switching to a Dictionary object for variable storage to setup for future parts in this series.</p>



<h2 class="wp-block-heading">Linear Interpolation</h2>



<p>Last time we used a static animation step that was calculated in advance to modify the width of our element. That method is fine for many uses, but for more advanced things we want to get a bit more involved with linear interpolation.</p>



<p>The new method will shorten the steps taken if something locks up your application UI so the time you’ve chosen for your animation to take to complete is honored. Previously, if something suspended your application’s main thread, the animation would halt and wait during this period and 250ms could become 100ms before the lockup and 150ms after the lockup. Now, if your selected animation time is 250ms and something suspends UI updates, the animation will complete after the UI updates have resumed as if the UI had never become unresponsive, resulting in a true animation time that roughly matches the specified time (I’ve seen +/- approximately 0.03 seconds using this method with a timer set at the minimum period for the debugging OS).</p>



<h3 class="wp-block-heading">What is Linear Interpolation</h3>



<p>Linear interpolation (or lerp) in animation is used to calculate change based on the total amount of time a process should take, the amount of time passed since the start of the process, and the change in value from start to finish. By using these three values we can determine, at any given point within our animation time-frame, what our current value should be.</p>



<p>You can read more in-depth information about linear interpolation&nbsp;<a href="https://en.wikipedia.org/wiki/Linear_interpolation" target="_blank" rel="noreferrer noopener">here</a>.</p>



<h3 class="wp-block-heading">What Does it Look Like?</h3>



<p>In code, linear interpolation is a fairly simple algorithm. We provide the following:</p>



<ul class="wp-block-list"><li>Starting value (starting width, in our case)</li><li>Ending value (the width after animation)</li><li>The amount of time passed (expressed as a double value between 0 and 1, which is typically referred to as alpha)</li></ul>



<pre class="wp-block-preformatted">Private Function lerp(startValue as Double, endValue as Double, alphaValue as Double) as Double
   '// The lerp function evaluates where we should be in the animation
   '   given a starting point, an ending point, and the amount of time
   '   elapsed. Lerp is shorthand for linear interpolation.
   return (startValue * (1 - alphaValue)) + (endValue * alphaValue)
 End Function</pre>



<p>We can express that graphically with the two red points below representing our starting and ending values, the blue line representing the current position between those two values over time.</p>



<figure class="wp-block-image"><img decoding="async" src="https://ci3.googleusercontent.com/proxy/-8kFNcU0N2t_1hvzbfiBMOT6UYFoOB_gonR7QiYArtDLFjvJQrYKU9v5GVNXwasTiF72iReaHhpK4yy0af8Ci8dhHHT2iiaTHX6nkqkHKxaKU5uNRlp9Bs-35Lu--8mp_5WWY9RG4Zdxv-RcHB4VLxgxkCahRIrM5-VePASmvvOymqzGF0Ig=s0-d-e1-ft#https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/LinearInterpolation.svg/1920px-LinearInterpolation.svg.png" alt=""/></figure>



<p>By&nbsp;<a rel="noreferrer noopener" href="https://commons.wikimedia.org/wiki/User:Berland" target="_blank">Berland</a>. Based on png-version&nbsp;<a rel="noreferrer noopener" href="https://commons.wikimedia.org/wiki/File:Linear_interpolation.png" target="_blank">Image:Linear_interpolation.png</a>. Newer version by&nbsp;<a rel="noreferrer noopener" href="https://commons.wikimedia.org/wiki/User:Krishnavedala" target="_blank">ElectroKid</a>&nbsp;&#8211; Own work, Public Domain,&nbsp;<a rel="noreferrer noopener" href="https://commons.wikimedia.org/w/index.php?curid=2415345" target="_blank">Link</a></p>



<h2 class="wp-block-heading">Applying Linear Interpolation</h2>



<p>Applying this to our previous code requires quite a bit of modification.</p>



<p>First, we need to keep track of when the animation started, the width value when it started, and what we want our width to be at the end. Previously we used properties of the AnimatedCanvas class to track each value we used in our animation. In this version we’re going to use a Dictionary to store values and keep that in a property of the canvas. This gives us a means of throwing away the animated values (setting our Dictionary property to Nil) when we’re not using them, mainly, but also looks a bit cleaner in the Properties listing in our project, and sets up for the future of this project.</p>



<h3 class="wp-block-heading">Properties</h3>



<p>We’re going to add a new property to our AnimatedCanvas class which will hold our calculation values during the animation process:</p>



<pre class="wp-block-preformatted">Private Property animAction as Dictionary</pre>



<p>With the addition of this property, we’re going to get rid of our old animStep property.</p>



<h3 class="wp-block-heading">MouseUp Event</h3>



<p>Our MouseUp handler is quite a bit different in this implementation. Instead of calculating the animation steps based on the timer’s interval and the length of time we want our animation to run, we’re now doing the following:</p>



<pre class="wp-block-preformatted">Sub MouseUp(X As Integer, Y As Integer) Handles MouseUp
   '// Just in case we hit some strange scenario where
   '   the timer is disposed of. Should, theoretically,
   '   never happen in this case, but better safe than sorry.
   if IsNull( animTimer ) then Return
 '// Now we're going to check for a currently running
   '   animation. If we find that the timer is currently
   '   running, then we know that the user wants to
   '   animate in the other direction. All we need to do
   '   is switch the direction the animation is running.
   if animTimer.Mode = 2 then
     expanded = not expanded
   end if
 '// Here we create our dictionary object containing
   '   everything our Timer's action event needs to do
   '   the work. The current time in Microseconds, which
   '   will be our start time, the start width, and the
   '   expected resulting width. This "10" is hard-coded
   '   just so that we can actually click on the canvas
   '   again to reverse the animation if it is fully
   '   collapsed. In most scenarios you wouldn't have
   '   a hard-coded value like this and you may even be
   '   triggering the animation from a different element
   '   altogether, so this value is purely for demonstation
   '   purposes in this project.
   animAction = new Dictionary( "s" : Microseconds, "sw" : Width, "ew" : If( expanded, 10, expandedWidth ) )
 '// Finally, enable the timer to perform the animation.
   animTimer.Mode = 2
 '// We've added this event, just in case there's
   '   something you want to trigger at the start of the
   '   animation.
   RaiseEvent BeforeAnimate
 End Sub</pre>



<p>As you can see from the comments above, we’re constructing the Dictionary object with the current time(s), the current width(w), and the expected width at the end of the animation(ew).</p>



<p>These changes also allow for the user to click again during the animation to reverse it without, theoretically, causing any strangeness such as animation skipping or jumping. The new animation operation just begins when the user clicks, cancelling the old one. Since we’re using linear interpolation, the timer’s Action event handler just keeps trucking along with a calculated width based upon the changes.</p>



<h3 class="wp-block-heading">Timer Action Handler</h3>



<p>Our timer’s action handler method is also quite different. This is where we use the Dictionary we created in the MouseUp event handler and assigned to our animAction property to calculate and apply the new width of our component.</p>



<pre class="wp-block-preformatted">Private Sub animTimer_Action(sender as Timer)
   '// In this version we've moved from having properties to store
   '   the values we use in our animation to a dictionary
   '   because it's both data we don't want to keep around when not 
   '   animating, and it'll be a bit easier to implement multiple
   '   running animations later by looping over an array of these
   '   dictionary objects on each Timer action.
 '// Our first step is to make sure we actually have an animation
   '   to perform.
   if IsNull( animAction ) then
     '// No current animation. The timer shouldn't even be running,
     '   so we'll go ahead and kill it. Theoretically this should
     '   never happen, but it's another case of checking just so
     '   we're not using unnecessary CPU cycles.
     sender.Mode = 0
     Return
   end if
 '// Now we'll get our operation values from the dictionary object.
   '   it is possible to run into KeyNotFoundExceptions here, since
   '   we're not checking first, but if you do, then you've likely
   '   made an error when modifying the code since we create the
   '   Dictionary with the same set of keys every time and always
   '   overwrite the old object with the new one.
   dim animStart as Double = animAction.Value("s").DoubleValue
   dim animStartWidth as Double = animAction.Value("sw").DoubleValue
   dim animEndWidth as Double = animAction.Value("ew").DoubleValue
 '// timePercent is used in the lerp function and gives us a basis
   '   for dividing up the distance we need to cover in to constituent
   '   pieces for animating. We also use this for cutting out of the
   '   animation at the appropriate time. This value ranges from
   '   0 to 1.0. We subtract our start time from the current time in
   '   microseconds, then divide by one thousand to convert that in to
   '   milliseconds. We then divide the result of that by our AnimationTime
   '   as that's already expressed in milliseconds.
   dim timePercent as Double = (((Microseconds - animStart) / 1000) / manimTime)
 '// Here we pass our start value, end value, and the percentage
   '   of time passed to our lerp function parameters to
   '   calculate what the current width should be at this point
   '   in the total animation time. Note that, in our previous
   '   version, we used a step value and modified our current width
   '   but in this version our step value is the entire calculated
   '   current width.
   dim animStep as Double = Lerp( animStartWidth, animEndWidth, timePercent )
 '// If we've reached our ending width or our alotted time has
   '   passed then we bail and set the values we expect at the
   '   end of the animation.
   if animStep = animEndWidth or timePercent &gt;= 1 then
     me.Width = animEndWidth ' Set our width to the end result.
     expanded = not expanded ' Toggle the state boolean.
     animAction = nil ' Set our dictionary to nil since we don't need it.
     sender.Mode = 0 ' Disable the Timer
     RaiseEvent AfterAnimate ' Notify that the animation is done.
 <code>Return ' Bail out.</code>
 end if
 '// If we get here, then we're still somewhere in the middle
   '   of the animation. Apply the new width value, and we're
   '   good to go.
   me.Width = animStep
 End Sub</pre>



<h2 class="wp-block-heading">New Events</h2>



<p>For this version, I’ve also added a couple of new events. These can be used to perform other actions that you may want to carry out when the animation process has started or ended. Here’s our two new event definitions:</p>



<pre class="wp-block-preformatted">Event AfterAnimate()
Event BeforeAnimate()</pre>



<h2 class="wp-block-heading">Other Changes</h2>



<p>When you launch the demo project, you’ll notice that there’s a lot more going on with wndAnimate than the previous version. First, I renamed the animTime property to a computed AnimationTime property and added it to the inspector, so there’s a field on the window to change this value.</p>



<p>Second, there’s a new checkbox captioned “Insert Interruption”. This uses the BeforeAnimate event to cause the app’s main thread to sleep for 50% of the animation time beginning at 25% of the animation time, which results in the UI becoming unresponsive and the animation to halt for the duration of the Sleep. Once the call to sleep is complete, you’ll see the animation pick up where it would have been if there had been no call to sleep.</p>



<p>Then, a group of RadioButtons for verifying that modal elements do not interfere with animation on the main thread. The choices are: None, MenuItem, and Modal Window. When Xojo was still using Carbon for macOS, modal elements would interfere with UI updates to the main window until that modal element was dismissed. There’s all sorts of technical-ness as to why, but all we really care about is that with the move to Cocoa this is no longer an issue, and the demo proves it.</p>



<p>Finally, I’ve moved the instance of AnimatedCanvas to the right of the Window. This isn’t purely aesthetic as I plan to use this setup in a future version to show how to run multiple concurrent animations.</p>



<p>You can download the updated demo project&nbsp;<a rel="noreferrer noopener" href="https://graffitisuite.com/downloads/ms_17049.zip" target="_blank">here</a>.</p>



<p><em>Anthony G. Cyphers is the Lead Developer and Sole Proprietor of&nbsp;</em><a rel="noreferrer noopener" href="https://graffitisuite.com/" target="_blank"><em>GraffitiSuite Solutions</em></a><em>, and has been providing custom Xojo components and contract development since 2003. He runs the&nbsp;</em><a rel="noreferrer noopener" href="https://t.co/WQSD3O2V6R" target="_blank"><em>Xojo User’s Discord server</em></a><em>, and is an administrator in the&nbsp;</em><a rel="noreferrer noopener" href="https://www.facebook.com/groups/xojo.dev/" target="_blank"><em>Xojo User’s Facebook user group</em></a><em>.</em></p>



<div class="wp-block-image"><figure class="alignleft is-resized"><img loading="lazy" decoding="async" src="https://blog.xojo.com/wp-content/uploads/2019/07/AnthonyAndLaura_Small.png" alt="" class="wp-image-5959" width="117" height="119" srcset="https://blog.xojo.com/wp-content/uploads/2019/07/AnthonyAndLaura_Small.png 375w, https://blog.xojo.com/wp-content/uploads/2019/07/AnthonyAndLaura_Small-296x300.png 296w" sizes="auto, (max-width: 117px) 100vw, 117px" /></figure></div>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Guest Post: Animating Xojo, Part 1</title>
		<link>https://blog.xojo.com/2019/07/24/guest-post-historical-methods/</link>
		
		<dc:creator><![CDATA[Anthony Cyphers]]></dc:creator>
		<pubDate>Wed, 24 Jul 2019 10:00:44 +0000</pubDate>
				<category><![CDATA[Guest Post]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Animation]]></category>
		<category><![CDATA[UI]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=5889</guid>

					<description><![CDATA[One of the fun things I get to do regularly is build animations into Xojo desktop components. While incredibly rewarding when you get it right, it can be a long road.]]></description>
										<content:encoded><![CDATA[
<p>One of the fun things I get to do regularly is build animations into Xojo desktop components. While incredibly rewarding when you get it right, it can be a long road.</p>



<span id="more-5889"></span>



<h2 class="wp-block-heading">Historical Methods</h2>



<h3 class="wp-block-heading">The Tight Loop</h3>



<p>A long time ago, to implement animation in Xojo one had to resort to tight loops if the animation needed to be self-contained (in a custom class, for example). This resulted in code that looked a lot like this:</p>



<pre class="wp-block-preformatted">while me.Height &gt; 0
     me.Height = me.Height - 10
     me.Refresh()
     App.DoEvents(10)
 Wend</pre>



<p>Now, however, this is bad for a number of reasons. The most obvious being the use of a tight loop for UI updates. This can result in all kinds of funkiness that’s hard to workaround, and often the code above would’ve been much longer to account for other issues in the UI depending upon your implementation.</p>



<p>Second, the use of Refresh(), Refresh was required because the changes were happening in a tight loop, but it comes with its own set of drawbacks, and there are no shortage of forum posts that detail why to avoid it.</p>



<p>Third, App.DoEvents. Don’t. Use. DoEvents. I can’t stress this enough. Unless building a console app, DoEvents should almost always be avoided. As pointed out in&nbsp;<a rel="noreferrer noopener" href="https://forum.xojo.com/conversation/post/75304" target="_blank">this post</a>, if you think you need DoEvents in a desktop app, you probably actually need a thread.</p>



<h3 class="wp-block-heading">Threads</h3>



<p>Using threads for animation can be a great way to implement it depending on the scenario, but one must remember that threads can no longer access the UI. At one time, however, they could. This gave us the ability to take that tight loop above and shove it in to a thread to avoid locking up the UI and using DoEvents. A typical thread animation Run() event might’ve looked like this:</p>



<pre class="wp-block-preformatted">Sub Run() Handles Run
   while me.Height &gt; 0
     control1.Height = control1.Height - 10
     control1.Refresh()
     me.Sleep(10)
   Wend
 End Sub</pre>



<p>While this was an improvement as it moved the tight loop out of the primary event loop, the old implementation of threads that allowed for directly accessing the UI came with its own set of problems and was unsafe.</p>



<h2 class="wp-block-heading">Today</h2>



<p>Nowadays, the best method is to use a timer. If we want a self-contained animation, then this requires a bit of setup. I’m creating a new class called AnimatedCanvas that shrinks or expands its width when clicked. Its superclass is Canvas.</p>



<h3 class="wp-block-heading">The Properties</h3>



<p>Once we have that, we’re going to add some properties to it:</p>



<pre class="wp-block-preformatted">Private Property expandedWidth as Integer
 Private Property animStep as Integer
 Private Property animTimer as Timer
 Private Property expanded as Boolean = True</pre>



<p>The expandedWidth property is where we’re going to store the width we want when the control is expanded fully.</p>



<p>animStep is where we’ll store the current animation’s step value, or the amount of change to the width at each stage of the animation.</p>



<p>animTimer is our Timer instance that will be doing the heavy-lifting.</p>



<p>The expanded boolean property helps us determine what operation is currently in progress. We set it to True because we’re going to use the default width of the control as our expandedWidth property later on.</p>



<h3 class="wp-block-heading">The Event Handlers</h3>



<p>The first event handler we want to add is the Open event. In this simple example we’re just setting our expandedWidth property to the width of the component, and setting up our animTimer property for use later.</p>



<pre class="wp-block-preformatted">Sub Open() Handles Open
   '// In this example, I'm just setting the expandedWidth to the initial width.
   '   A real-world case would obviously be different.
   expandedWidth = me.Width
 '// Initialize our animation timer. I'm using a period of 20 here,
   '   but this should be adjusted for best performance and smoothness
   '   based on what you're animating.
   animTimer = new Timer
   animTimer.Period = 20
   animTimer.Mode = 0
   AddHandler animTimer.Action, WeakAddressOf animTimer_Action
 End Sub</pre>



<p>Next we’re just going to do something simple in the Paint event so that we can see what’s going on</p>



<pre class="wp-block-preformatted">Sub Paint(g As Graphics, areas() As REALbasic.Rect) Handles Paint
   '// Just fill it red so that we can see it.
   g.ForeColor = &amp;cff0000
   g.FillRect( 0, 0, g.Width, g.Height )
 End Sub</pre>



<p>MouseDown is also simple. We want our animation to occur only if the control is enabled, so we can just return the value of Enabled. If Enabled, then MouseUp will fire next to start our animation.</p>



<pre class="wp-block-preformatted">Function MouseDown(X As Integer, Y As Integer) Handles MouseDown as Boolean
   Return me.Enabled
 End Function</pre>



<p>MouseUp is a little more complex as we’re doing some simple math for animStep and then starting the timer.</p>



<pre class="wp-block-preformatted">'// Just in case we hit some strange scenario where
 '   the timer is disposed of. Should, theoretically,
 '   never happen in this case, but better safe than sorry.
 if IsNull( animTimer ) then Return
 '// Here we setup our animation step to take 1000ms.
 '   We multiple by 20, which is our timer interval.
 '   The minimum built-in timer Interval for macOS
 '   is 10ms and for Windows is 16ms, if I remember
 '   correctly. 20 gets us where want to be, but
 '   could just as easily use a #IF target or the
 '   value of 16.
 animStep = (expandedWidth / 1000) * 20
 '// If our control is currently expanded, then we'll
 '   use a negative value to shrink it.
 if expanded then animStep = -animStep
 '// Finally, enable the timer to perform the animation.
 animTimer.Mode = 2</pre>



<h3 class="wp-block-heading">Timer Action</h3>



<p>Now that we have all of that setup, the last thing we need to do is add our timer’s Action handler method. This is going to do the bulk of the work by calculating the new width, checking the new width for validity, then either applying the new value or ending the animation.</p>



<pre class="wp-block-preformatted">Private Sub animTimer_Action(sender as Timer)
 ‘// We want to calculate the new value ahead of time.
 ’   This gives us the opportunity to bail a little
 '   earlier and not have to apply a corrected value later.
 dim newWidth as Integer = me.Width + animStep
 ' If expanded = True then we’re shrinking.
 if expanded then
  ‘// If our newWidth is going to be less than or equal to
  ’   our minimum width, then we’re done with our animation.
  '   I’m using a hardcoded width of 10 here, but you could
  '   create a property for this.
  if newWidth &lt;= 10 then    
   ‘// Make sure the width is correct for the new state,    
   ’   disable the timer, then set our Expanded property.    
   me.Width = 10    
   sender.Mode = 0    
   expanded = False    
   Return  
 end if 
else  
‘// If our newWidth is going to be greater than or equal  
’   to our expandedWidth, we bail.  
if newWidth &gt;= expandedWidth then
    ‘// Make sure the width is correct for the new state,
    ’   disable the timer, then set our Expanded property.
    me.Width = expandedWidth
    sender.Mode = 0
    expanded = True
    Return
  end if
 end if
 '// If we get here, then we're still somewhere in the middle
   '   of the animation. Apply the new width value.
   me.Width = newWidth
 End Sub</pre>



<h3 class="wp-block-heading">Final Notes</h3>



<p>As you can see, animating in Xojo is a fairly simple concept at its core. The real fun starts when you want to animate multiple virtual elements inside picture objects with varying types of animation, and we won’t even get in to&nbsp;<a href="https://developers.google.com/web/fundamentals/design-and-ux/animations/the-basics-of-easing" target="_blank" rel="noreferrer noopener">easing</a>.</p>



<p>Bear in mind that this is an intentionally simplistic example that’s meant to illustrate the basics of timer-based animation. A full implementation that expects multiple different moving parts in tandem or independently would be much more complex, and likely use something along the lines of an Array or Dictionary to keep track of the animation queue and the expected changes at each step in the process.</p>



<p>I’ve built all of this in to an example project, which you can download&nbsp;<a rel="noreferrer noopener" href="https://graffitisuite.com/downloads/ms_16917.zip" target="_blank">here</a>.</p>



<p><em>Anthony G. Cyphers is the Lead Developer and Sole Proprietor of&nbsp;</em><a rel="noreferrer noopener" href="https://graffitisuite.com/" target="_blank"><em>GraffitiSuite Solutions</em></a><em>, and has been providing custom Xojo components and contract development since 2003. He runs the&nbsp;</em><a rel="noreferrer noopener" href="https://t.co/WQSD3O2V6R" target="_blank"><em>Xojo User&#8217;s Discord server</em></a><em>, and is an administrator in the&nbsp;</em><a rel="noreferrer noopener" href="https://www.facebook.com/groups/xojo.dev/" target="_blank"><em>Xojo User&#8217;s Facebook user group</em></a><em>.</em></p>



<figure class="wp-block-image is-resized"><img loading="lazy" decoding="async" src="https://blog.xojo.com/wp-content/uploads/2019/07/AnthonyAndLaura_Small.png" alt="" class="wp-image-5959" width="106" height="108" srcset="https://blog.xojo.com/wp-content/uploads/2019/07/AnthonyAndLaura_Small.png 375w, https://blog.xojo.com/wp-content/uploads/2019/07/AnthonyAndLaura_Small-296x300.png 296w" sizes="auto, (max-width: 106px) 100vw, 106px" /></figure>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Canvas: How to Create Custom UI Controls</title>
		<link>https://blog.xojo.com/2019/04/15/canvas-how-to-create-custom-ui-controls/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Mon, 15 Apr 2019 10:00:47 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[AprendeXojo]]></category>
		<category><![CDATA[Beginner Tips]]></category>
		<category><![CDATA[Canvas]]></category>
		<category><![CDATA[iOSCanvas]]></category>
		<category><![CDATA[Multi-Platform Development]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[User Interface]]></category>
		<category><![CDATA[WebCanvas]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=5649</guid>

					<description><![CDATA[Sometimes, subclassing the available controls is the answer to add specific behaviors you need. But what happen when none of the controls offer what you need, whether visually or functionally? The answer is the Canvas class (for Desktop projects), WebCanvas class (for Web projects) and iOSCanvas class for iPhone and iPad devices. ]]></description>
										<content:encoded><![CDATA[<p>Xojo includes a good amount of <b>UI</b> controls available from the Library for <strong>Desktop</strong>, <strong>Web</strong>, <strong>iOS</strong> and <strong>Raspberry Pi</strong> targets. These are the pieces that allow you to layout the user interface of your apps: properties, methods and events that, when combined, define the specific behavior of the project at hand.</p>
<p>Sometimes, subclassing the available controls is the answer to add specific behaviors you need. But what happen when none of the controls offer what you need, whether visually or functionally? The answer is the Canvas class (for Desktop projects), WebCanvas class (for Web projects) and iOSCanvas class for iPhone and iPad devices. But how do you create your own UI controls from scratch? Read on to learn&#8230;<span id="more-5649"></span></p>
<p>Before starting with this basic tutorial about customized UI controls, there is much more to take into consideration about providing the same behavior on your designed controls for multiplatform deployments. For example, in the case of desktop projects, we should add to the mix some things like <strong>HiDPI</strong> / <strong>Retina</strong> detection and adaptation on the fly (specially in the case of Windows deployment, with multiple dpi / Windows OS version combinations), and <strong>Dark Mode</strong> support for macOS. A well as other performance hints and differences when it&#8217;s about doing desktop multiplatform layouts; for example, when to set the <code>Transparent</code> or <code>DoubleBuffer</code> properties to <code>True</code> or not.</p>
<p>As the name implies, the Canvas control acts like a painting canvas and you can set its look for all the supported states based on the available events. This is done through the <code>Paint</code> Event and all the <a href="http://documentation.xojo.com/api/graphics/graphics.html"><b>Graphic</b></a> classes availables in the Framework. In fact, the <b>Paint</b> event provides as a parameter the graphical context (canvas height and width) you can paint on. In addition, you can combine these graphic classes (or completely substitute them) with any prepared <b>Picture</b> of your choice as the customize control background (<a href="http://documentation.xojo.com/getting_started/using_the_ide/image_set_editor.html"><b>ImageSet</b></a> recommended, so it supports all the needed resolutions based on display dpi). In addition, and as you can do with the drawing via the Graphic class and functions, you can choose to use a different <a href="http://documentation.xojo.com/api/graphics/picture.html"><b>Picture</b></a> as the control background based on several events, for example, when the mouse pointer is entering or exiting the control limits in a Desktop or Web app, or as response to the user clicking on it.</p>
<h2>Canvas: A matter of Events</h2>
<p>The <a href="http://documentation.xojo.com/api/deprecated/canvas.html">Canvas class</a> provides all the needed Events you probably would want to implement in order to react to the user interaction. These are listed and described in the available documentation online and as part of the Xojo IDE interactive Help.</p>
<p>While you can drag and drop a Canvas instance directly to your project layout window or view, implementing and writing the code associated with  any of the available Events, the recommended way to go is to create your own subclass taking as its parent the Canvas class. This way, you can implement and fine-tune every aspect that makes you control unique and, most importantly, re-use your customized UI controls as many times you want both in current and future projects (or even <a href="https://documentation.xojo.com/Resources:Free_Source_Code_and_Tools">offer them</a> to the Xojo community or <a href="https://www.xojo.com/store/#addons">sell them</a> to other developers!).</p>
<p>As you probably already know, in an <b>OOP programming language</b>, subclassing is the method to get a specialized behavior from an existing Class: We get for free all the available properties, methods and events from the parent (and all its parent hierarchy), including also the code executed in the Paint event to truly paint or provide its look on screen; so we just need to implement the specific behavior and/or control drawing/painting we need over these.</p>
<p>This is also the way to go when you are in the inital stages of designing your own customized UI control: will you need to create even more specialized behaviors based on a &#8220;parent&#8221; or base customized control? Maybe variations on the behavior? In cases like these, you should define your UI control base class at the bare-minimum set of painting, behavior (events and methods) and properties that will be shared from all the future UI Controls inherited from your base/parent UI Control class. (i.e: more specialized or with behavior variations).</p>
<p>Creating a subclass in Xojo is truly simple: just drag and drop the Canvas icon from the <b>Library</b> to the <b>Navigator</b> (the leftmost column in the Xojo IDE), or choose <code>Insert &gt; Class</code> from the Insert menu.</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-5650 aligncenter" src="https://blog.xojo.com/wp-content/uploads/2019/04/Canvas-Library.png" alt="" width="260" height="317" /></p>
<h2>Points vs Pixels: HiDPI and Retina</h2>
<p>Once you have added the new Class to your project, select it, go to the Inspector and set the name you want to use for your new Class (using a &#8220;company&#8221; or personal prefix it&#8217;s always a good idea to avoid collision with other existing or future classes in the Xojo Framework, or when using third party classes). Then, in the <b>Super</b> field of the Inspector Panel, type <code>Canvas</code> and confirm the entry. You&#8217;ll see how your class icon changes to the one that uniquely identifies Canvas based classes and instances. The most important thing: your new subclass will have all the properties, events and methods you may expect from a Canvas.</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-5651 aligncenter" src="https://blog.xojo.com/wp-content/uploads/2019/04/Subclase-Canvas.png" alt="" width="261" height="234" /></p>
<p>This will be the base class in our short tutorial for creating a customized button that will change its associated image (picture) when the mouse pointer is inside the button area, outside the button bounds or when the user click on the control. In the last case, the button will change both the image and its internal state represented by a property as a Boolean value (named <code>Status</code>).</p>
<p>As our customized UI control will not draw itself via the Paint event, we will need to design the images so these precisely fit in the size we want to use for our button. In this example a size of 32 x 32 points.</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-5652 aligncenter" src="https://blog.xojo.com/wp-content/uploads/2019/04/Sketch-Graficos-1024x650.png" alt="" width="1024" height="650" /></p>
<p>In general, when designing images to use in our Xojo projects we need to change our mindset from thinking in pixels to points. That&#8217;s because Xojo apps do support <b>HiDPI</b> on Windows/Linux and <b>Retina</b> on macOS; that is: hi-def graphics. Thus, it&#8217;s important to use a design tool that simplifies the process. Personally, I use the vectorial app Sktech on macOS because it automates the 2x creation of the final images. (Remember that HiDPI/Retina is enabled by default in the Building Settings on every new Desktop project.)</p>
<p>How do you support HiDPI/Retina if you want to draw the control look on the fly? Avoid the use of pixels in your calculations or when setting the values of the existing Graphic class properties, and use Points instead. If you really need to access the Pixels values underneath, then you can resort to the <code>RGBSurface</code> class (if available) and make use of the <code>ScaleFactorChanged</code> event available on the Canvas class. This way, your class will be notified on every change between displays with or withour Retina/HiDPI support.</p>
<p>Good rule of thumb: do all your control drawing inside the Paint event! And, when you need to update or redraw it (maybe as consequence of some change in the app behavior, or from the change made in other UI control), invoke the method <code>Invalidate</code> instead of <code>Refresh</code>. In general, this will speed up the drawing and, thus, the main app performance.</p>
<h2>If you use an existing Event… Define the Event again</h2>
<p>As our customized class makes use of the <b>Open</b>, <b>MouseEnter</b>, <b>MouseExit</b> and <b>MouseDown</b> Events, we need to make sure we define these events again to the class, so they are also available for the developer using our canvas-based UI subclass. After all, it&#8217;s very probable he needs or wants to add extra code on top of ours! This is something we can do choosing <code>Add to "class_name" &gt; Event definition</code> when our subclass icon is selected in the Navigation Browser.</p>
<p>Thus, once we have created the same events (using the same parameters and returning the same kind of Type values as the original ones), we need to make sure we call them; usually as the last line of code for the already used Event. For example, this is the code for our implementation of the <code>MouseDown</code> event in our Canvas subclass:</p>
<pre>me.Backdrop = if(me.Status = false, ShellRunSelected, ShellRun)
me.Status = not me.Status
return RaiseEvent MouseDown(X, Y)</pre>
<p>Note how, in this case, our implementation of the <code>MouseDown</code> event returns the value returned by the consumer of our subclass instances, called with the <code>RaiseEvent</code> statement. Just remember that returning the <code>True</code> value from this event means that such events will not be propagated further along the Events Chain.</p>
<h2>Putting it all Together</h2>
<p>With this information at hand, and the basic concepts explained, <a href="https://youtu.be/7NYwpdXN-SA">this video</a> (in Spanish) shows how you can join all the needed pieces: pictures, events, definition of already consumed events by the subclass; creating a new very basic control from scratch. Obviously, from this point on, you can find in the available documentation all the information needed to create more complex UI controls based on the Canvas class (WebCanvas or iOSCanvas). The possibilities are limitless!</p>
<p>Other useful topics:</p>
<ul>
<li><a href="https://documentation.xojo.com/topics/user_interface/desktop/desktop_controls/canvas.html">User Guide: Desktop Canvas</a></li>
<li><a href="https://documentation.xojo.com/api/deprecated/canvas.html">Canvas</a>, <a href="https://documentation.xojo.com/api/graphics/graphics.html">Graphics</a> classes</li>
<li><a href="https://documentation.xojo.com/UserGuide:iOS_Canvas">User Guide: iOS Canvas</a></li>
<li><a href="https://documentation.xojo.com/topics/user_interface/web/controls/canvas.html">User Guide: Web Canvas</a></li>
</ul>
<p><em>Javier Rodri­guez has been the Xojo Spanish Evangelist since 2008, he’s also a Developer, Consultant and Trainer who has be using Xojo since 1998. He manages <a href="http://www.aprendexojo.com">AprendeXojo.com</a> and is the developer behind the GuancheMOS plug-in for Xojo Developers, Markdown Parser for Xojo, HTMLColorizer for Xojo and the Snippery app, among others.</em></p>
<p>*<a href="https://www.aprendexojo.com/2016/10/canvas-crea-tus-propios-controles/">Read this post in Spanish</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>#JustCode Challenge Week 8 &#8211; JumpStart App Launcher</title>
		<link>https://blog.xojo.com/2018/08/10/justcode-challenge-week-8-jumpstart-app-launcher/</link>
		
		<dc:creator><![CDATA[Paul Lefebvre]]></dc:creator>
		<pubDate>Fri, 10 Aug 2018 10:10:46 +0000</pubDate>
				<category><![CDATA[Fun]]></category>
		<category><![CDATA[#JustCode]]></category>
		<category><![CDATA[Atari]]></category>
		<category><![CDATA[Canvas]]></category>
		<category><![CDATA[ContainerControl]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[UI]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=4815</guid>

					<description><![CDATA[Replicating an app launcher he originally made for the Atari, Paul's JumpStart app for week 8 of #JustCode demonstrates save/load JSON, ContainerControl and Canvas-based Buttons in Xojo.]]></description>
										<content:encoded><![CDATA[<p>A long, long time ago (1989) one of the first apps I ever made was an app launcher for the Atari ST. I called it JumpSTART. I originally wrote it in <a href="https://en.wikipedia.org/wiki/GFA_BASIC">GFA BASIC</a> and then later re-implemented it in <a href="https://en.wikipedia.org/wiki/Pascal_(programming_language)">Pascal</a> (<a href="https://archive.org/details/OSSPersonalPascal">OSS Personal Pascal</a>, technically).</p>
<p>When I got my first modem I went online with <a href="https://en.wikipedia.org/wiki/GEnie">Genie</a> and <a href="https://en.wikipedia.org/wiki/Delphi_(online_service)">Delphi</a> and uploaded JumpSTART as freeware. Even though it was freeware, I got a few checks in the mail from people that liked it.</p>
<p>I was reminded of JumpSTART when I saw my dock getting crowed. I thought replicating JumpSTART in Xojo would be a good project for week 8 of #JustCode. Though let&#8217;s just call it JumpStart this time around.</p>
<p><span id="more-4815"></span></p>
<p>This is what JumpSTART looked like on monochrome 640&#215;480 screen:</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-4816 aligncenter" src="https://blog.xojo.com/wp-content/uploads/2018/08/2018-08-09_14-06-09.png" alt="" width="640" height="434" /></p>
<p>JumpStart in Xojo is greatly simplified and looks like this:</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-4817 aligncenter" src="https://blog.xojo.com/wp-content/uploads/2018/08/2018-08-09_14-10-06.png" alt="" width="680" height="392" /></p>
<p>The Xojo version automatically saves and loads the apps you&#8217;ve added so there was no need for separate Load/Save, Re-Read buttons. Technically they don&#8217;t have to be apps as even a document file can be launched as well.</p>
<p>You can right-click on an app button after you&#8217;ve added it to Rename, Change or Clear it so that also removed the need for some UI controls. And you just click on an empty button to add an app to it. When you click on a button with an app assigned, the app is launched and JumpStart hides itself.</p>
<p>This Xojo app demonstrates the use of a Canvas-based button, ContainerControls added dynamically to a window, and saving/loading JSON. The Canvas-based button will let me tweak the display, colors and maybe display an icon there.</p>
<p>You can <a href="http://files.xojo.com/JustCode/JumpStart.xojo_binary_project.zip">download the project</a> or <a href="https://gitlab.com/xojo/JumpStart">check it out on GitLab</a>.</p>
<p>As an added code treat, I&#8217;ve posted the <a href="https://github.com/paullefebvre/JumpSTART-AtariST">original JumpSTart Pascal code to GitHub</a>. FWIW, the original Pascal source is just over 1300 lines of code. The Xojo version is about 180.</p>
<p>Add your #JustCode project to the <a href="https://forum.xojo.com/49298-just-code-challenge-week-8-projects">week 8 forum conversation</a>.</p>
<p>Download and check out earlier projects:</p>
<ul>
<li>Week 7: <a href="https://blog.xojo.com/2018/08/03/justcode-challenge-week-7-pitch-tracker/">Pitch Tracker</a></li>
<li>Week 6: <a href="https://blog.xojo.com/2018/07/27/justcode-challenge-week-6-bubble-popper/">Bubble Popper</a></li>
<li>Week 5: <a href="https://blog.xojo.com/2018/07/20/justcode-challenge-week-5-math-quiz/">Math Quiz</a></li>
<li>Week 4: <a href="https://blog.xojo.com/2018/07/13/justcode-challenge-week-4-mini-golf-scorekeeper/">Mini-Golf ScoreKeeper</a></li>
<li>Week 3: <a href="https://blog.xojo.com/2018/07/06/just-code-challenge-week3/">Dogs Up!</a></li>
<li>Week 2: <a href="https://blog.xojo.com/2018/06/29/just-code-challenge-week2/">Password Generator</a></li>
<li>Week 1: <a href="https://blog.xojo.com/2018/06/22/just-code-challenge-week1/">Color Picker</a></li>
</ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Create Your Own ImageWell Based on Canvas</title>
		<link>https://blog.xojo.com/2018/05/07/create-your-own-imagewell-based-on-canvas/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Mon, 07 May 2018 10:00:26 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Canvas]]></category>
		<category><![CDATA[Graphics]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[Xojo Framework]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=4179</guid>

					<description><![CDATA[Whether you are using Xojo to create your very first application or if you are coming from other languages, like C# or VisualBasic, customized UI controls are probably one of those things you have in your to-do list. For multiplatform Desktop apps, you will find that the Canvas class offers everything you need.]]></description>
										<content:encoded><![CDATA[<p>Whether you are using Xojo to create your very first application or if you are coming from other languages, like <strong>C#</strong> or <strong>VisualBasic</strong>, customized UI controls are probably one of those things you have in your to-do list. For multiplatform Desktop apps, you will find that the <a href="http://developer.xojo.com/canvas"><b>Canvas</b></a> class offers everything you need. In order to show you how easy it can be, follow this tutorial to recreate the <a href="http://developer.xojo.com/imagewell"><b>ImageWell</b></a> UI class control, provided by default in the Xojo framework. Our customized ImageWell will be able to proportionally display any JPEG file dropped by the user on the control, centering it on the available surface.<span id="more-4179"></span></p>
<p>Along the way, we also will see how the Xojo IDE simplifies making subclass properties available from the Inspector Panel, so when using their instances we can set some attributes as the background color, pen size or border color in a more convenient way.</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-4182 aligncenter" src="https://blog.xojo.com/wp-content/uploads/2018/04/MyImageWellFinal.png" alt="" width="712" height="534" />As usual, the first step to create a new subclass is adding a new class item to the Desktop project (Insert &gt; Class). With the new class item selected, change its name to something descriptive. For this example we will use <code>MyImageWell</code>. The most important thing here is setting <code>Canvas</code> as its <b>Super</b> attribute. That means that the subclass will be based on the <b>Canvas</b> class, inheriting all its properties, Events and Methods so they will also be available for the subclass.</p>
<p>One of these inherited Events is <b>Open</b>, and we will implement it using the Event Handler option (click the <strong>+</strong> button in the toolbar to access the dropdown menu) in order to inform the class that we want to accept the dropped JPEG files. This is done with the following line of code in the Open Event Handler:</p>
<p><code>Me.AcceptFileDrop("img/jpeg")</code></p>
<p>Obviously, we can extend this support to accept other Xojo compatible graphical formats. For that, we would add a new <a href="http://developer.xojo.com/userguide/using-file-type-sets"><b>File Type Set</b></a> to the project, using it as the filter in the previous line of code.</p>
<p>Once we inform the class that we accept this feature, the next step is implementing the <b>DropObject</b> Event Handler that fires once this action is detected inside the limits of the control. The code we need to write for this Event Handler will test that the <code>obj</code> parameter passed along contains a valid <b>FolderItem</b> and, in that case, we will load such file as a new <b>Picture</b> object, assigning it to a property of the same Type. The code for the event is:</p>
<pre>If obj.FolderItemAvailable Then
  image = Picture.Open(obj.FolderItem)
  Invalidate
End If</pre>
<p>Don&#8217;t forget to add the <code>Image</code> computed property to the Class using Insert &gt; Computed Property while the <code>MyImageWell</code> item is still selected, and using these values:</p>
<ul>
<li><b>Name</b>: Image</li>
<li><b>Type</b>: Picture</li>
<li><b>Scope</b>: Public</li>
</ul>
<p>As you can see, the amount of code we need to load the file as a Picture object and to assign it to the class property is minimal! Why do we use the <b>Invalidate</b> method call afterwards? Well, this is responsible for informing the operating system to redraw the instance when it has a chance. And when this happens it will fire the third and last Event we need to implement: <b>Paint. </b>Here is where we can instruct any Canvas based control how to draw itself through the graphical context represented by the <strong><code>g</code></strong> parameter passed along the Event.</p>
<h2>Painting the control</h2>
<p>Once we&#8217;ve added the <b>Paint</b> Event to the class and before writing the code responible of painting the dropped image inside its limits, we need to add three additional computed properties. We will use them to set some attributes like the color we want to use to paint the control background, the border color and even the width of the border:</p>
<ul>
<li><code>BackGroundColor As Color = &amp;cdddddd</code></li>
<li><code>BorderColor As Color = &amp;c000000</code></li>
<li><code>PenSize as Integer = 2</code></li>
</ul>
<p>Add to the Setter method on every computed property the sentence me.invalidate; so every time we assign a new value to them… the control will be redrawn using the new value (background color, border color, pen size or even a new assigned picture).</p>
<p>The last step is writing the code responsible for drawing the control itself: filling the background with the set color, then drawing proportionally (and centered) the loaded picture pointed by the <code>Image</code> property, and finally drawing the border with the width and color specified. All of this is what we can do using the following snippet of code:</p>
<pre>// We fill the control background using the set color
g.DrawingColor = BackgroundColor
g.FillRectangle(0,0,g.Width,g.Height)

// If we have a valid image object, then we draw it centered and scaled (if necessary)
If image &lt;&gt; Nil Then 
  Var Height, Width As Integer
  Var sourcey, sourcex As Integer = 0 
  If image.Height &gt; image.Width Then
    Height = Me.Height
    Width = (Me.Height * image.Width) / image.Height
    sourcey = (Me.Width - Width) / 2
  Else
    Width = Me.Width
    Height = (Me.Width * image.Height) / image.Width
    sourcex = (Me.Height - Height) / 2
  End If

  // This is the line that actually draws a picture inside the graphic context of our instance
  g.DrawPicture(image,sourcey,sourcex,Width,Height,0,0,image.Width,image.Height)
End If

// We draw the control border
g.PenSize = me.PenSize
g.DrawingColor = BorderColor

g.DrawRectangle(0,0,Me.Width,Me.Height)</pre>
<p>As you can see, the code needed for this is also very simple!</p>
<h2>Make the properties visible from the Inspector Panel</h2>
<p>While we are on it, we can use the <b>Inspector Behavior</b> feature to make our specific properties visible through the Inspector Panel. This way, when we add new instances from the subclass to the layout of any window, we will be able to easily set their values directly from the Inspector Panel. With the <code>MyImageWell</code> item still selected in the Project Browser, use the contextual menu to select the <b>Inspector Behavior</b> option to access the following Window:</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-4180 aligncenter" src="https://blog.xojo.com/wp-content/uploads/2018/04/InspectorBehavior.jpg" alt="" width="721" height="459" /></p>
<p>Here you will see all the Class properties, those common to all <b>Canvas</b> derived subclasses and also the ones added for us and that are specific to our class. You can find these properties listed under the <b>Behavior</b> section. To make them visible in the Inspector Panel we just need to check their associated checkboxes; and even modify their default values editing the associated cell if we want to.</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-4181 aligncenter" src="https://blog.xojo.com/wp-content/uploads/2018/04/InspectorPanelOwnClass.png" alt="" width="322" height="257" /></p>
<p>Now, we just need to drag and drop the <code>MyImageWell</code> item from the Project Browser into any Window Design Layout in order to add new instances! Once we run the example project, we will see how the controls react to displaying any JPEG picture dropped on it.</p>
<p>If you want, you can investigate deeper into the methods provided by the <a href="http://developer.xojo.com/graphics"><b>Graphics</b></a> class in order to make the control more glittery or more sophisticated.</p>
<p>You can watch <a href="https://www.youtube.com/watch?v=val_Bcgw_4U">this video</a> (en español) to see this in action:</p>
<p><em>Javier Rodri­guez has been the Xojo Spanish Evangelist since 2008, he’s also a Developer, Consultant and Trainer who has be using Xojo since 1998. He manages <a href="http://www.aprendexojo.com">AprendeXojo.com</a> and is the developer behind the GuancheMOS plug-in for Xojo Developers, Markdown Parser for Xojo, HTMLColorizer for Xojo and the Snippery app, among others</em></p>
<p>*<a href="https://www.aprendexojo.com/2018/04/crea-tu-propio-imagewell-con-canvas/">Read this post in Spanish</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Improve Your Project&#8217;s Look &#8211; Windows UI Tips</title>
		<link>https://blog.xojo.com/2018/04/18/improve-your-projects-look-windows-ui-tips/</link>
					<comments>https://blog.xojo.com/2018/04/18/improve-your-projects-look-windows-ui-tips/#comments</comments>
		
		<dc:creator><![CDATA[Paul Lefebvre]]></dc:creator>
		<pubDate>Wed, 18 Apr 2018 10:00:29 +0000</pubDate>
				<category><![CDATA[Tips]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Canvas]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[Virtual Machine]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=4126</guid>

					<description><![CDATA[Here are some tips that will help ensure your Windows apps look and feel their best, with Xojo 2018 Release 1 now that Windows apps now have a more stable and flicker-free UI than ever before.]]></description>
										<content:encoded><![CDATA[<p>With Xojo 2018 Release 1 now available, Windows apps now have a more stable and flicker-free UI than ever before. In order to provide these improvements, Xojo and your apps do ask a bit more from Windows. Here are some tips that will help ensure your Windows apps look and feel their best.</p>
<h2>Set Transparent Property for Controls to False</h2>
<p>UI controls now have a Transparent property which determines whether the control is transparent on Microsoft Windows. The default is False for new controls added to layouts. For existing projects and controls, this property is set to True for maximum compatibility.<br />However, controls that have Transparent set to True require more drawing, use more memory and are thus slower. For best results you should set the Transparent property to False for as many controls as possible.</p>
<h2>Consider ContainerControl DoubleBuffer Property</h2>
<p>Set this property to True to reduce flicker on Microsoft Windows when the ContainerControl is scrolled. Otherwise you can leave this to False.</p>
<h2>Avoid Overlapping Controls</h2>
<p>The easiest thing you can do to prevent flickering is to not overlap any controls. Overlapped controls result in more requests to redraw the controls which can result in flickering and slower performance.</p>
<h2>Use a Canvas</h2>
<p>For best results, display any graphics using the Paint event of a Canvas control. Stay away from using the Window Backdrop property, the Window Paint event, the Canvas.Backdrop property or the ImageWell control. Although those techniques work fine in certain situations, they often lead to flickering in more complex window layouts.</p>
<p><del>On the Canvas, the first thing you want to do is turn off the EraseBackground property. The EraseBackground property prevents the Canvas from being erased (and showing as a white rectangle) before it is redrawn, which is another common source of flicker</del>. (<a href="https://documentation.xojo.com/api/deprecated/canvas.html.EraseBackground">Deprecated</a> in Xojo 2019r2) You should also check your usage of the DoubleBuffer property. In many cases you will find you can leave it set to off (False) for best performance.</p>
<p>With these tweaks, you can do all your drawing in the Paint event using the supplied graphics object parameter: g.</p>
<p><strong>Note: Do not do any drawing directly to the Canvas.Graphics property.</strong> This ability was deprecated in 2011 and is strongly discouraged. Drawing in this manner will likely increase flickering and will definitely slow down graphics updates.</p>
<p>You can have separate methods that update the graphics, but they need to be called from the Paint event with the graphics object supplied to the methods as a parameter. Another technique is to have a Picture property that you use to draw you graphics to and then in the Paint event handler you draw the Picture to the Canvas to display it.</p>
<p>When you want the Canvas to update itself, redrawing any changes to your graphics, you call the Invalidate method:</p>
<pre>Canvas1.Invalidate(False)</pre>
<p>You can also call the Refresh method:</p>
<pre>Canvas1.Refresh(False)</pre>
<p>The difference is that Invalidate tells the Canvas to update itself when it gets a redraw request from the operating system. The Refresh method tells the Canvas to update itself immediately. Normally you want to use Invalidate as it results in fewer draw requests, improving performance and reducing flicker.</p>
<p>To reduce flicker, both of the above commands pass False for the EraseBackground parameter (which defaults to True) so that the Canvas is not erased before its updated contents are drawn.</p>
<h2>Remove or Update Older Code</h2>
<p>If you previously had specialized code in your app to help minimize Windows flicker, you should consider removing it as the code may prove to be unnecessary and cause worse performance.</p>
<h2>A Note About Virtual Machines</h2>
<p>Many people run Windows in Virtual Machines. If you do so you&#8217;ll want to ensure that you have the best performance possible. Xojo apps use Direct2D for all screen drawing and not all VM software has properly accelerated graphics drivers for this.</p>
<p>In particular, VMware Fusion has rather poor performance when &#8220;Accelerate 3D Graphics&#8221; is enabled in the Display preferences. For best performance you should make sure that option is turned off.</p>
<p>Alternatively, Parallels Desktop and VirtualBox both seem to have better graphics performance with Direct2D and Xojo apps.</p>
<p>For more information:</p>
<ul>
<li><a href="http://developer.xojo.com/windows-ui-guidelines">Windows UI Guidelines</a></li>
</ul>


<p>*Minor update re: deprecation 3/2021</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.xojo.com/2018/04/18/improve-your-projects-look-windows-ui-tips/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>THIS IS NOT A DRILL: Poor Interface Design and its Potentially Dangerous Impact</title>
		<link>https://blog.xojo.com/2018/01/16/this-is-not-a-drill-poor-interface-design-and-its-potentially-dangerous-impact/</link>
		
		<dc:creator><![CDATA[Geoff Perlman]]></dc:creator>
		<pubDate>Tue, 16 Jan 2018 22:08:58 +0000</pubDate>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Design]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[User Interface]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=3728</guid>

					<description><![CDATA[This warning, as well all now know, turned out to be a false alarm accidentally set off by a state employee who was attempting to perform an internal test. Let's please not spend $1 million or more of the taxpayer's hard-earned money on a $100 fix. With this simple, 5 minute fix, it would be nearly impossible for someone to accidentally send out a warning when they meant to only perform an internal test.



The first thing that went through my mind was how exactly is such an important function of a state emergency management system triggered so easily that it could be done by accident? It is my hope that every member of every similar emergency management team around the world with a similar system is rechecking that system now to see how poorly or well-designed their user interface is.]]></description>
										<content:encoded><![CDATA[<p>As most of you know, this past Saturday morning, the people of Hawaii got a shocking notification on their smartphones warning of a <strong>incoming ballistic missile</strong> and that this warning was <strong>not a drill</strong>. I can only imagine the fear that raced through the minds of more than a million people. This warning, as well all now know, turned out to be a false alarm accidentally set off by a state employee who was attempting to perform an internal test.</p>
<p><span id="more-3728"></span></p>
<p>The first thing that went through my mind was how exactly is such an important function of a state emergency management system triggered so easily that it could be done by accident? Did a radar system show an incoming missile that was later discovered to be a mistake? No. As the Washington Post <a href="https://www.washingtonpost.com/news/post-nation/wp/2018/01/14/hawaii-missile-alert-how-one-employee-pushed-the-wrong-button-and-caused-a-wave-of-panic/?utm_term=.db7f46a108c3">reported</a>, the user interface for the system has a drop down menu with two items: <em>Test Missile Alert</em> and <em>Missile Alert</em>. The facts that these two options are so similarly named and that there is no confirmation dialogue for such an important command is at a minimum bad user interface design.</p>
<p>If I want do something as relatively innocuous as erasing all the data from my iPhone, I have to first find the feature that does this buried two levels deep in the Settings app where it&#8217;s clearly titled, &#8220;Erase All Contents and Settings.&#8221; Tapping it displays a dialog box asking me if I want to <em>Backup Then Erase</em> or just go ahead and <em>Erase Now</em>. If memory serves from the last time I did this, choosing Erase Now then reconfirms that I truly do want to erase all the contents and settings on my iPhone. That&#8217;s a lot of steps to accomplish a task that only affects one person: me. However, considering the magnitude of the result, it makes good sense that the user interface doesn&#8217;t make this very easy to do and actual makes sure you are deliberately trying to erase your phone.</p>
<p>Hawaii&#8217;s emergency management system does none of this. There apparently are just two menu items, one next to the other and once chosen, the computer immediately completes the task without confirmation. That&#8217;s just astonishing. What&#8217;s even worse, however, than the poor interface design on the part of whomever designed it, is that at a minimum (a) someone had to accept this poor interface design, (b) others had to use it without complaint that it could potentially cause the very situation it has caused.</p>
<p>The Chairman of the FCC wants an an <a href="https://www.commondreams.org/news/2018/01/15/will-ajit-pais-fcc-probe-hawaii-false-alarm-expose-role-telecom-giants-played">expensive investigation</a>. Let&#8217;s please not spend $1 million or more of the taxpayer&#8217;s hard-earned money on a $100 fix. First, these two menu items should be reduced to a single menu item entitled, &#8220;Missile Alert&#8230;&#8221; The ellipsis tells the user that before this item performs its function, a dialog will be displayed to confirm it. The dialog that appears should be on that requires deliberate actions by the user to initiate a true warning to the population of Hawaii:</p>
<p><img loading="lazy" decoding="async" class="alignleft size-full wp-image-3738" src="https://blog.xojo.com/wp-content/uploads/2018/01/Screen-Shot-2018-01-16-at-3.39.55-PM.png" alt="" width="1000" height="390" /></p>
<p>&nbsp;</p>
<p>In the above example dialog box notice that in order to initiate a real warning, the user will not only have to uncheck the &#8220;Internal Test Only&#8221; checkbox but also have to deliberately click the Proceed button as the Cancel button is the default.</p>
<p>After taking those two deliberate actions, the user is then presented with a second dialog box to confirm that requires again clicking the Proceed button, another deliberate action.</p>
<p>&nbsp;</p>
<p><img loading="lazy" decoding="async" class="alignleft size-full wp-image-3746" src="https://blog.xojo.com/wp-content/uploads/2018/01/Screen-Shot-2018-01-16-at-4.52.11-PM.png" alt="" width="1128" height="408" /></p>
<p>With this simple, 5 minute fix, it would be nearly impossible for someone to accidentally send out a warning when they meant to only perform an internal test.</p>
<p>Not all user interfaces have functions with such wide-reaching results. However, user interface guidelines for many years now have said that <strong>an action that cannot be undone should be confirmed</strong>. That&#8217;s a simple rule that all of us that design user interfaces would do well to remember.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>First Impressions Matter: 8 Surefire User Interface Design Tips</title>
		<link>https://blog.xojo.com/2017/07/20/first-impressions-matter-8-surefire-user-interface-design-tips/</link>
		
		<dc:creator><![CDATA[Paul Lefebvre]]></dc:creator>
		<pubDate>Thu, 20 Jul 2017 06:52:05 +0000</pubDate>
				<category><![CDATA[Learning]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Design]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[User Interface]]></category>
		<guid isPermaLink="false">http://blog.xojo.com/?p=2699</guid>

					<description><![CDATA[With today's development tools, it's easy to create user interfaces for your apps. Here are 8 tips to help ensure you create UIs that your users will love.]]></description>
										<content:encoded><![CDATA[<p>Your app&#8217;s user interface makes the first impression with your user and is vitally important to its success. With today&#8217;s modern development tools, it&#8217;s easy to create great <a href="https://en.wikipedia.org/wiki/User_interface_design">user interfaces</a> for your app.</p>
<p>Here are 8 proven tips to help ensure you create a user interface that your users will love.</p>
<p><span id="more-2699"></span></p>
<p><strong>1. Limit choices.</strong><br />
Don’t provide an overwhelming number of options or preferences for your users. Too many choices can be intimidating and confusing and can make people not enjoy using your app. Your job is to design the software, which means choosing what it should do. Don&#8217;t take the easy way out and provide loads of options for your users all at one time.</p>
<p><strong>2. Be familiar.</strong><br />
Sometimes you may need to implement an entirely new user interface metaphor in order to design your app. But typically this is unnecessary. Though it can be fun creating new and snazzy UI layouts, your users will likely not appreciate them much. Why? Because they won’t understand them or won’t know how to use them. A unique UI design isn&#8217;t always practical &#8211; stick to what people are familiar with.</p>
<p><strong>3. Be consistent.</strong><br />
Your app should be consistent within itself. Don’t use UI controls in different ways on different screens because that is just confusing. For example, don&#8217;t use buttons on one screen to indicate actions, but then use link text on another screen to indicate the same action.</p>
<p><strong>4. Put the user in charge.</strong><br />
Let the user feel like they are controlling the software. This means don’t force them down a single path to solve something. Let them try things and make mistakes. Have an undo feature so that they can easily fix their mistakes.</p>
<p><strong>5. People can&#8217;t.</strong><br />
Don’t spend time writing long text for the user as they likely won’t read it. Keep the language short and simple. Make it easy for people to enter text because they are not good at it. If the user has to enter lots of text, give them lots of room, enable a spell checker and use a larger font to make it easier for them to read the text.</p>
<p>Make your UI targets easy to find and use because people can’t control the mouse, trackpad or even their finger for touch devices. And lastly, users likely won’t remember how they did something the last time, so make it easy to figure out.</p>
<p><strong>6. Design first.</strong><br />
Have a design process &#8211; it doesn’t need to be anything complex. Sketching designs on paper or a whiteboard is a great way to get a feel for things. Software to mockup UI designs (such as <a href="http://balsamiq.com/" target="_blank" rel="noopener noreferrer">Balsamiq</a>) can also be quite useful. You can also use development tools like Xojo to mockup UI designs, but be careful not to make your mockup too functional or the users might think it is nearly complete!</p>
<p><strong>7. Time is relative.</strong><br />
Users perceive time differently than you might expect. For example, they typically hate waiting for tasks to complete. But if you make it seem like they are not waiting, they often don’t notice how long a task takes. For example, if your main window takes 5 seconds to appear, that will irritate your users. If you instead display the window immediately with a loading indicator, users are far less likely to notice the delay. In general, users more easily notice delays when the UI becomes unresponsive so try to minimize that.</p>
<p>Also keep in mind that features you have spent a large amount of time creating may only be used for a very short period of time. Don’t let yourself become comfortable with a difficult design because you use it frequently.</p>
<p><strong>8. Help out.</strong><br />
Your app should provide assistance to your users. Tips and guides are a great way to gently remind users how to use your software. It’s also a great idea to provide default data for the first launch of your app so that users can see how it is actually used in the real world. Another strategy is to prevent the user from making a mistake in the first place. Disable things when they cannot be used and enable them when they can be used.</p>
<p>For more tips like these, I recommend <a href="http://www.apress.com/us/book/9781893115941">User Interface Design for Programmers by Joel Spolsky</a>.</p>
<p>If you want to try your next app in Xojo, <a href="http://www.xojo.com/download/">download</a> it free anytime.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Set iOS App Icon Badge Number</title>
		<link>https://blog.xojo.com/2016/06/17/set-ios-app-icon-badge-number/</link>
		
		<dc:creator><![CDATA[Paul Lefebvre]]></dc:creator>
		<pubDate>Fri, 17 Jun 2016 00:00:00 +0000</pubDate>
				<category><![CDATA[iOS]]></category>
		<category><![CDATA[Declares]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[UI]]></category>
		<guid isPermaLink="false">http://blogtemp.xojo.com/2016/06/17/set-ios-app-icon-badge-number/</guid>

					<description><![CDATA[Learn how to create Declares to iOS classes and methods to set the app icon badge number.]]></description>
										<content:encoded><![CDATA[<p>I&#8217;m sure you&#8217;ve all seen the iOS Mail app, which displays the number of unread messages in a small red badge in the top right of the app icon. You can do this too with your Xojo app and the magic of the Declare command.</p>
<p><span id="more-316"></span></p>
<p>A quick glance at the iOS <a href="https://developer.apple.com/reference/uikit/uiapplication">UIApplication</a> doc page shows that there is a property called <a href="https://developer.apple.com/reference/uikit/uiapplication/1622918-applicationiconbadgenumber?language=objc">applicationIconBadgeNumber</a> that is the &#8220;number currently set as the badge of the app icon in Springboard.&#8221;</p>
<p>So how can this be used with Xojo? Using just five Declare commands, which I&#8217;ll cover step-by-step.</p>
<p>At first glance, it seems like it is as simple as using the property to set the badge number. Well, it used to be that simple in iOS 7 and earlier. But starting with iOS 8, you are now required to first get the user&#8217;s permission by calling the <a href="https://developer.apple.com/reference/uikit/uiapplication/1622932-registerusernotificationsettings?language=objc">registerUserNotificationSettings</a> method on UIApplication. Looking at that page, you&#8217;ll see that to register for a notification, you have to supply an instance of UIUserNotificationSettings that is configured for badge icon permission. So I&#8217;m going to start there.</p>
<p>But before jumping right in, there is a helper function I need in order to get references to iOS classes: NSClassFromString. So this is the <strong>first Declare</strong> and it looks like this:</p>
<pre>Declare Function NSClassFromString Lib "Foundation" (name As CFStringRef) As Ptr</pre>
<p>Now I can get a reference to <a href="https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIUserNotificationSettings_class/">UIUserNotificationSettings</a> by calling this method:</p>
<pre>Dim notificationSettings As Ptr = NSClassFromString("UIUserNotificationSettings")</pre>
<p>This class has a shared method (<a href="https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIUserNotificationSettings_class/#//apple_ref/occ/clm/UIUserNotificationSettings/settingsForTypes:categories:">settingsForTypes:categories:</a>) that can be called to get an instance configured for use with registerUserNotificationSettings. Its Declare (<strong>our second</strong>) looks like this:</p>
<pre>Declare Function settings Lib "UIKit" Selector "settingsForTypes:categories:" _
  (obj As Ptr, allowedTypes As Integer, actionSettings As Ptr) As Ptr</pre>
<p>Looking at that method declaration, note the trailing colon in the name. This is necessary because the method takes parameters. Do not forget to include it or the method will not be found and your app will crash when you run it.</p>
<p>The first parameter (obj As Ptr) is for you to pass in the reference to the UIUserNotificationSettings class. The second parameter (allowedTypes As Integer) is the type of notification you want to use, and the third parameter (actionSettings As Ptr) is for groups of notifications, but I won&#8217;t be using that.</p>
<p>You can now call the method by supplying the reference to the class we have stored in notificationSettings. For the allowedTypes, the value &#8220;1&#8221; indicates a badge icon notification:</p>
<pre>Dim settingsObject As Ptr = settings(notificationSettings, 1, Nil)</pre>
<p>This gives me an instance of UIUserNotificationSettings that I can then pass to the registerUserNotificationSettings method. In order to call that method I now need a reference to the UIApplication instance for the running app. To get that the <strong>third Declare</strong> is needed:</p>
<pre>Declare Function sharedApplication Lib "UIKit" Selector "sharedApplication" (obj As Ptr) As Ptr</pre>
<p>The Declare to call that method looks like this:</p>
<pre>Dim sharedApp As Ptr = sharedApplication(NSClassFromString("UIApplication"))</pre>
<p>This is the <strong>fourth declare</strong> to the registerUserNotificationSettings method:</p>
<pre>Declare Sub registerUserNotificationSettings Lib "UIKit" Selector "registerUserNotificationSettings:" _
  (obj As Ptr, settings As Ptr)</pre>
<p>You call this method by passing in the reference to the shared app and the settings:</p>
<pre>registerUserNotificationSettings(sharedApp, settingsObject)</pre>
<p>Lastly, we arrive at the <strong>fifth and final declare</strong> which calls the applicationIconBadgeNumber property that was the first thing I identified. Its Declare looks like this:</p>
<pre>Declare Sub applicationIconBadgeNumber Lib "UIKit" Selector "setApplicationIconBadgeNumber:" _
  (id As Ptr, value As Integer)</pre>
<p>One thing to note is that because this is a property, the name has to be adjusted a bit. Rather than using &#8220;applicationIconBadgeNumber&#8221;, you have to use the name of the &#8220;setter&#8221;, which prefixes &#8220;set&#8221; and tweaks the casing. So the name instead is &#8220;setApplicationIconBadgeNumber:&#8221;. Remember the trailing colon since a parameter is passed!</p>
<p>And don&#8217;t forget that these Selector names are all case-sensitive!</p>
<p>And finally, you call the method like this to set the number 42 on the badge:</p>
<pre>applicationIconBadgeNumber(sharedApp, 42)</pre>
<p>You&#8217;ll have to press home to get back to Springboard so you can see the app icon with the badge, of course!</p>
<p><img loading="lazy" decoding="async" style="display: block; margin-left: auto; margin-right: auto;" src="https://blog.xojo.com/wp-content/uploads/2016/06/IconBadgeNumber.pngt1466486449161ampwidth320ampheight590" sizes="auto, (max-width: 320px) 100vw, 320px" alt="IconBadgeNumber.png" width="320" height="590" /></p>
<p>You can <a href="http://files.xojo.com/BlogExamples/IconBadgeNumber.xojo_binary_project.zip">download the project</a> that adds this as an extension method to iOSApplication so you can call it like this:</p>
<pre>App.SetBadge(42)</pre>
<p>And you are all set now!</p>
<p><!--HubSpot Call-to-Action Code --> <span id="hs-cta-wrapper-e647e3ff-c813-4005-8e7e-170f214d8cea" class="hs-cta-wrapper"> <span id="hs-cta-e647e3ff-c813-4005-8e7e-170f214d8cea" class="hs-cta-node hs-cta-e647e3ff-c813-4005-8e7e-170f214d8cea"><br />
<!-- [if lte IE 8]>


<div id="hs-cta-ie-element"></div>


<![endif]--> <a href="http://blog.xojo.com/2016/05/18/ios-view-navigation-tips/" target="_blank"><img loading="lazy" decoding="async" id="hs-cta-img-e647e3ff-c813-4005-8e7e-170f214d8cea" class="hs-cta-img aligncenter" style="border-width: 0px; margin: 0 auto; display: block; margin-top: 20px; margin-bottom: 20px;" src="https://blog.xojo.com/wp-content/uploads/2016/05/e647e3ff-c813-4005-8e7e-170f214d8cea.png" alt="Xojo iOS Tips View Navigation Blog Post" width="596" height="107" align="middle" /></a></span></span> <!-- end HubSpot Call-to-Action Code --></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>iOS View Navigation Tips</title>
		<link>https://blog.xojo.com/2016/05/18/ios-view-navigation-tips/</link>
		
		<dc:creator><![CDATA[Paul Lefebvre]]></dc:creator>
		<pubDate>Wed, 18 May 2016 00:00:00 +0000</pubDate>
				<category><![CDATA[iOS]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[App Store]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[UI]]></category>
		<guid isPermaLink="false">http://blogtemp.xojo.com/2016/05/18/ios-view-navigation-tips/</guid>

					<description><![CDATA[Your iOS apps uses Views to display information to the user, learn to use the multiple views to show different information.]]></description>
										<content:encoded><![CDATA[<p>Your iOS apps uses Views to display information to the user and often your app will have multiple views to show different information. These views can be displayed in different ways.</p>
<p><span id="more-293"></span></p>
<h2>PushTo</h2>
<p>The most common way to display new views is to use the <a href="http://developer.xojo.com/iosview$PushTo">PushTo</a> method.</p>
<p>With this method, the new view appears on top of the current view and a &#8220;back&#8221; button is displayed in the Navigation Bar (if it is enabled) to close this new view so that the original view is displayed.</p>
<p><a href="http://files.xojo.com/BlogExamples/PushToExample.xojo_binary_project.zip">Download the PushTo example</a> to see how this works.</p>
<p>Refer to <a href="http://developer.xojo.com/userguide/ios-views">Views</a> in the User Guide to learn more about PushTo.</p>
<h2>Modal View</h2>
<p>A modal view is a view that appears over a view, and is a bit more limited. The user cannot display a new view or go back to the original view until the modal view is closed. To display a modal view in your Xojo iOS apps, you have to use a Declare.</p>
<p><a href="http://files.xojo.com/BlogExamples/ModalView.xojo_binary_project.zip">Download the ModalView example</a> to see how it works.</p>
<p>Refer to <a href="http://developer.xojo.com/userguide/ios-views">Views</a> in the User Guide to learn more about Modal View.</p>
<h2>Change Current Screen</h2>
<p>There are times where you may want to reset the view hierarchy so that the &#8220;back&#8221; feature is not available. An example of this might be an initial login screen displayed by your app. After the user logs in, you will likely want your true main view to replace the login view, but not allow the use of the &#8220;back&#8221; feature to go back to the login view.</p>
<p>A feature (<a href="http://developer.xojo.com/iosapplication$CurrentScreen">iOSApplication.CurrentScreen</a>) added to Xojo in 2016r1 allows you to do that by changing the current screen of the app to point to your new view.</p>
<p><a href="http://files.xojo.com/BlogExamples/NavigationExample.xojo_binary_project.zip">Download the Navigation example</a> to see how it works.</p>
<p>Refer to <a href="http://developer.xojo.com/userguide/ios-views">Views</a> in the User Guide to learn more about this.</p>
<h2>Splits on iPad</h2>
<p>An iPad can be set up with a split view that allows two views to be displayed on the screen at the same time. The view on the left is the &#8220;master&#8221; and the view on the right is the &#8220;detail&#8221;. If you&#8217;ve used Mail on iOS then you&#8217;re familiar with this type of layout.</p>
<p>When you have a split view set up, you can access the base view for the master and detail areas by using the <a href="http://developer.xojo.com/iosview$ParentSplitView">ParentSplitView</a> property of any of the views. ParentSplitVIew is an iOSSplitView with its own properties (Master and Detail) that give you access to the content of the split area.</p>
<p><a href="http://files.xojo.com/BlogExamples/SplitViewExample.xojo_binary_project.zip">Download the SplitVIew example</a> to see how it works.</p>
<p>These tips should help you provide great navigation for your iOS apps. If you have an iOS app in the App Store, be sure to tell everyone in the <a href="https://forum.xojo.com/20331-xojo-made-ios-apps-in-the-app-store">Xojo-made iOS apps in the App Store</a> conversation of the forum and tweet us the link @xojo!</p>
<p>We&#8217;ve got lots of resources to get your iOS app started, <a href="http://developer.xojo.com/ios-guide" target="_blank">check them out</a> or click below to learn about building 64bit iOS apps for the App Store.</p>
<p><!--HubSpot Call-to-Action Code --> <span id="hs-cta-wrapper-effd89b6-76da-4f82-a83a-cd6bd0e73903" class="hs-cta-wrapper"> <span id="hs-cta-effd89b6-76da-4f82-a83a-cd6bd0e73903" class="hs-cta-node hs-cta-effd89b6-76da-4f82-a83a-cd6bd0e73903"><br />
<!-- [if lte IE 8]>


<div id="hs-cta-ie-element"></div>


<![endif]--> <a href="http://blog.xojo.com/2015/02/25/creating-64-bit-ios-apps/" target="_blank"><img loading="lazy" decoding="async" id="hs-cta-img-effd89b6-76da-4f82-a83a-cd6bd0e73903" class="hs-cta-img aligncenter" style="border-width: 0px;" src="https://blog.xojo.com/wp-content/uploads/2015/02/effd89b6-76da-4f82-a83a-cd6bd0e73903.png" alt="Xojo iOS 64bit" width="574" height="128" /></a> </span><script src="https://js.hscta.net/cta/current.js" charset="utf-8">// <![CDATA[
<script type="text/javascript"><![CDATA[ hbspt.cta.load(608515, 'effd89b6-76da-4f82-a83a-cd6bd0e73903', {}); // ]]&gt;</script></span><br />
<!-- end HubSpot Call-to-Action Code --></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Headless Pi: Using Xojo and Raspberry Pi Without a Display</title>
		<link>https://blog.xojo.com/2016/03/30/headless-raspberry-pi-using-xojo-and-your-raspberry-pi-without-a-display/</link>
		
		<dc:creator><![CDATA[Paul Lefebvre]]></dc:creator>
		<pubDate>Wed, 30 Mar 2016 00:00:00 +0000</pubDate>
				<category><![CDATA[Raspberry Pi]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Console]]></category>
		<category><![CDATA[RPi]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">http://blogtemp.xojo.com/2016/03/30/headless-raspberry-pi-using-xojo-and-your-raspberry-pi-without-a-display/</guid>

					<description><![CDATA[Learn how to use Xojo and your Raspberry Pi without a display, but still connect to it to run apps.]]></description>
										<content:encoded><![CDATA[<p>You don&#8217;t need to hook up your Pi to a physical display, keyboard and mouse. You can set up <a href="https://en.wikipedia.org/wiki/Virtual_Network_Computing" target="_blank" rel="noopener">VNC</a> on the Pi so you can remotely connect to it.</p>
<p>My Raspberry Pi 2 sits on my desk next to one of my speakers. It&#8217;s not hooked up to any display. I use a combination of SSH, SFTP and VNC when I need to work with it.</p>
<p><span id="more-282"></span></p>
<p>To connect to the Pi, I just need its IP address, which currently is 10.0.1.11. I leave the Pi on all the time, but if I reboot it then the IP address could change since I have not set it up with a fixed IP address. To identify the IP address, I run the utility <a href="https://itunes.apple.com/us/app/lanscan/id472226235?mt=12">LanScan</a> (free on the Mac App Store) which shows me all the IP addresses of everything on my local network. The Raspberry Pi is clearly identified.</p>
<p><img loading="lazy" decoding="async" title="LanScan.png" src="https://blog.xojo.com/wp-content/uploads/2016/03/LanScan.pngt1466486449161ampwidth578ampheight266" sizes="auto, (max-width: 578px) 100vw, 578px" alt="LanScan.png" width="578" height="266" /></p>
<p>I can then connect to the Pi via ssh:</p>
<pre>ssh <a href="../../../com/xojo/blog/index.html">pi@10.0.1.11</a></pre>
<p>I&#8217;m prompted for the password, which I&#8217;ve left at the default (&#8220;raspberry&#8221;).</p>
<p>If I am only going to be running Xojo console apps, then this is all I need. You really only need to set up VNC if you want to access the Desktop so you can run Xojo desktop apps (or use the Pi UI to run other desktop apps).</p>
<p>Personally I do like using the Pi desktop, so I now need to start the VNC server, which I have previously installed. If you need to install it, easy <a href="https://www.raspberrypi.org/documentation/remote-access/vnc/">VNC installation steps</a> are at the official Raspberry Pi site.</p>
<p>At the ssh terminal, I start VNC using its defaults with this command:</p>
<pre>vncserver</pre>
<p>After typing this command, I&#8217;m back at the terminal prompt. Use the &#8220;exit&#8221; command to disconnect from the ssh connection.</p>
<p><img loading="lazy" decoding="async" title="Terminal.png" src="https://blog.xojo.com/wp-content/uploads/2016/03/Terminal.pngt1466486449161ampwidth578ampheight393" sizes="auto, (max-width: 578px) 100vw, 578px" alt="Terminal.png" width="578" height="393" /></p>
<p>Now I can connect to the Pi using a VNC client. I&#8217;m going to use the client that is built into OS X since it is always available and reasonably fast. In Finder, select Go-&gt;Connect to Server from the menu. In the window, enter the address and port for the VNC server and click Connect:</p>
<pre>vnc://10.0.1.11:5901</pre>
<p><img loading="lazy" decoding="async" title="VNCViewer.png" src="https://blog.xojo.com/wp-content/uploads/2016/03/VNCViewer.pngt1466486449161ampwidth578ampheight274" sizes="auto, (max-width: 578px) 100vw, 578px" alt="VNCViewer.png" width="578" height="274" /></p>
<p>You&#8217;ll again be prompted for your password. This is the password you set up when you installed TightVNC, not the Raspberry Pi password.</p>
<p>When everything connects you&#8217;ll get a window displaying the Raspberry Pi desktop, shown here running the XojoNotes example app:</p>
<p><img loading="lazy" decoding="async" title="PiDesktop.png" src="https://blog.xojo.com/wp-content/uploads/2016/03/PiDesktop.pngt1466486449161ampwidth578ampheight471" sizes="auto, (max-width: 578px) 100vw, 578px" alt="PiDesktop.png" width="578" height="471" /></p>
<p>But how do you get apps to the Pi so you can run them? I use SFTP. There are many SFTP tools available. I primarily use ForkLift and ExpanDrive, but other apps have also been recommended on the <a href="https://forum.xojo.com/30628-xojo-my-rasberry-pi-experience">Xojo forum</a>. Regardless of the tool you use, create a new SFTP connection and enter the same credentials you used to connect via ssh.</p>
<p>You&#8217;ll now have access to the file system on the Pi and you can drag files from your computer to the Pi&#8217;s file system, which will copy them across your network to the Pi. With ExpanDrive, I get a drive mounted to the Finder that is connected to the Pi, making access to the Pi always available.</p>
<p><img loading="lazy" decoding="async" title="ExpanDrive.png" src="https://blog.xojo.com/wp-content/uploads/2016/03/ExpanDrive.pngt1466486449161ampwidth578ampheight330" sizes="auto, (max-width: 578px) 100vw, 578px" alt="ExpanDrive.png" width="578" height="330" /></p>
<p>With your free Xojo Pi license you can develop and build desktop and console Pi apps. <a href="https://www.xojo.com/download/">Download</a> today and get the latest release!<span id="hs-cta-wrapper-aeb03183-a469-4f96-9547-7dd75111c681" class="hs-cta-wrapper"><span id="hs-cta-aeb03183-a469-4f96-9547-7dd75111c681" class="hs-cta-node hs-cta-aeb03183-a469-4f96-9547-7dd75111c681"><br />
</span></span><!-- end HubSpot Call-to-Action Code --></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Using Slack with Xojo</title>
		<link>https://blog.xojo.com/2015/11/30/using-slack-with-xojo/</link>
		
		<dc:creator><![CDATA[Paul Lefebvre]]></dc:creator>
		<pubDate>Mon, 30 Nov 2015 00:00:00 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[Slack]]></category>
		<category><![CDATA[UI]]></category>
		<guid isPermaLink="false">http://blogtemp.xojo.com/2015/11/30/using-slack-with-xojo/</guid>

					<description><![CDATA[A Xojo library for communicating with Slack.]]></description>
										<content:encoded><![CDATA[<p><a href="https://slack.com/">Slack</a> is a new business communication tool that is <a href="http://www.inc.com/magazine/201512/jeff-bercovici/slack-company-of-the-year-2015.html">taking the world by storm</a>. Here&#8217;s how you can use it with your Xojo apps.</p>
<p><span id="more-341"></span></p>
<p>As their tagline says, it&#8217;s a &#8220;messaging app for teams&#8221;. It&#8217;s also free to use (with a paid version also available) so it is easy for anyone to try.<img loading="lazy" decoding="async" title="" src="https://blog.xojo.com/wp-content/uploads/2015/11/slack-logo.jpgt1466486449161ampwidth578ampheight259" sizes="auto, (max-width: 578px) 100vw, 578px" width="578" height="259" /></p>
<p>Slack is pretty slick, making it incredibly easy to text chat with others on your team. I think it is much better than trying to use tools like iMessage, AIM or Skype for text chatting. With slack you can have multiple &#8220;channels&#8221; to keep converstations focused and attach files/images to a post. Slack has also been utterly reliable for me, unlike issues I&#8217;ve run into with iMessage and AIM.</p>
<p>To be fair, Slack doesn&#8217;t really offer anything all that new with regards to text chatting, but it integrates it all in a clean UI that is easily accessible by anyone.</p>
<p>Slack also has a <a href="https://api.slack.com/web">web api</a>, which of course works with Xojo. Back in September <a href="http://developer.xojo.com/webinar-using-slack">I did a webinar on a Slack library</a> It shows you how to allow your Xojo apps to post messages to a Slack channel and to get other information about your Slack teams and channels. This library is included in with the Xojo 2015 Release 3.1 examples (Communication/Web Services/Slack).</p>
<p>And now this Slack library is available on GitHub to make it easier to accept community contributions.</p>
<p><a href="https://github.com/xojo/slack">https://github.com/xojo/slack</a></p>
<p>To use the Slack library, you create an AuthToken for a Slack team account at the <a href="https://api.slack.com/web">Slack API site</a> (be sure to log in first).</p>
<p>Then you drag Slack.Connector onto your layout and call the Slack.Connector.SetAuthToken method with your token. The Open event handler is often a good place for this:</p>
<pre>SlackConnector.SetAuthToken("AFERE34323FJDK5") ' this is not an actual token</pre>
<p>Once authorized, you can call Connector methods to post message or get information about the Slack team and channels, with results returned to event handlers on Connector.</p>
<p>Refer to the <a href="https://github.com/xojo/slack">ReadMe on the GitHub page</a> for more information.</p>
<p>I hope you find it useful!</p>
<p><span id="hs-cta-wrapper-9e86dfb8-7d24-487b-a044-9a461c7f16ca" class="hs-cta-wrapper"><span id="hs-cta-9e86dfb8-7d24-487b-a044-9a461c7f16ca" class="hs-cta-node hs-cta-9e86dfb8-7d24-487b-a044-9a461c7f16ca"> <!-- [if lte IE 8]>


<div id="hs-cta-ie-element"></div>


<![endif]--> <a href="https://www.youtube.com/watch?v=D_iMQAjaxLA" target="_blank"><img loading="lazy" decoding="async" id="hs-cta-img-9e86dfb8-7d24-487b-a044-9a461c7f16ca" class="hs-cta-img aligncenter" style="border-width: 0px; margin: 0 auto; display: block; margin-top: 20px; margin-bottom: 20px;" src="https://blog.xojo.com/wp-content/uploads/2015/07/9e86dfb8-7d24-487b-a044-9a461c7f16ca.png" alt="Version Control Video Git" width="645" height="104" align="middle" /></a></span></span></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>There and Back Again: The Evolution of the Graphical User Interface</title>
		<link>https://blog.xojo.com/2014/07/29/there-and-back-again-the-evolution-of-the-graphical-user-interface/</link>
		
		<dc:creator><![CDATA[Geoff Perlman]]></dc:creator>
		<pubDate>Tue, 29 Jul 2014 00:00:00 +0000</pubDate>
				<category><![CDATA[Mac]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[GUI]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[UI]]></category>
		<guid isPermaLink="false">http://blogtemp.xojo.com/2014/07/29/there-and-back-again-the-evolution-of-the-graphical-user-interface/</guid>

					<description><![CDATA[Over the past 30 years, the GUI has evolved and in some ways has come full circle. If you are less than 25 years old, there's a very good chance you've never used a computer that didn't have a graphical user interface. But at the time, it was a radical departure from the way in which most people interacted with a computer. ]]></description>
										<content:encoded><![CDATA[<p>30 years ago this past January, Apple launched the Macintosh and with it, the first widely available computer with a Graphical User Interface or GUI. If you are less than 25 years old, there&#8217;s a very good chance you&#8217;ve never used a computer that didn&#8217;t have a graphical user interface. But at the time, it was a radical departure from the way in which most people interacted with a computer. <span style="line-height: 1.62;">Over the past 30 years, the GUI has evolved and in some ways has come full circle.</span></p>
<p><span id="more-141"></span><strong>In the Beginning</strong></p>
<p>In 1984 when the original Macintosh was introduced, as advanced as its interface was at the time, its graphics capabilities were extremely weak, at least by today&#8217;s standards. It could only manage a black and white, 1 bit interface.</p>
<p><a href="http://www.xojo.com/blog/en/assets_c/2014/07/Original%20Mac%20User%20Interface-444.php"><img decoding="async" class="mt-image-center" style="text-align: center; display: block; margin: 0px auto 20px; width: 400px;" title="1984_mac.png" src="https://blog.xojo.com/wp-content/uploads/2014/07/1984_mac.pngt1466486449161ampwidth400" sizes="(max-width: 400px) 100vw, 400px" alt="1984_mac.png" width="400" data-constrained="true" /></a>Almost 2 years later, Microsoft Windows 1.0 was released and it added color but was laboring under many of the same technological restrictions.</p>
<p><a href="http://www.xojo.com/blog/en/assets_c/2014/07/Windows1.0-447.php"><img decoding="async" class="mt-image-center" style="text-align: center; display: block; margin: 0px auto 20px; width: 400px;" title="windows_1.0.png" src="https://blog.xojo.com/wp-content/uploads/2014/07/windows_1.0.pngt1466486449161ampwidth400" sizes="(max-width: 400px) 100vw, 400px" alt="windows_1.0.png" width="400" data-constrained="true" /></a>The whole idea behind the GUI was to make the interface use elements that were similar to things the user already understood. For example, pushbuttons already existed in the real world. The idea of a window as a place to view things was an analogy but it connected the user with something they already understood.</p>
<p>Over time, the graphics capabilities of personal computers became stronger. Processors, memory and displays all became better, faster and less expensive. Consider Windows 95 (released in 1995) and Mac OS 8 (released in 1997):</p>
<p><a href="http://www.xojo.com/blog/en/assets_c/2014/07/Windows%2095-450.php"><img decoding="async" class="mt-image-center" style="text-align: center; display: block; margin: 0px auto 20px; width: 320px;" title="windows_95.png" src="https://blog.xojo.com/wp-content/uploads/2014/07/windows_95.pngt1466486449161ampwidth320" sizes="(max-width: 320px) 100vw, 320px" alt="windows_95.png" width="320" data-constrained="true" /></a><a href="http://www.xojo.com/blog/en/assets_c/2014/07/Mac_OS_8-453.php"><img decoding="async" class="mt-image-center" style="text-align: center; display: block; margin: 0px auto 20px; width: 320px;" title="mac_os_8.png" src="https://blog.xojo.com/wp-content/uploads/2014/07/mac_os_8.pngt1466486449161ampwidth320" sizes="(max-width: 320px) 100vw, 320px" alt="mac_os_8.png" width="320" data-constrained="true" /></a>Both took a big leap forward. With better graphics and color, the user interface felt more realistic. I know that may be hard to imagine if you never used these versions of Mac OS or Windows but remember and consider what users had been using up to this point. Over time, user interfaces became more skeuomorphic, though this was certainly true more for OS X than it was for Windows. Apple made the Address Book and Calendar   look somewhat like their real world counterparts.</p>
<h4>The Mobile User Experience</h4>
<p>When the iPhone came along, it took the mobile interface to an entirely new level. One of the things Apple realized is that when using an interface on a much smaller screen, you have to simplify. The busier the user interface, the harder it is to use. This meant fewer lines and simpler graphics. It also meant being more choosy about the functions apps would perform because of the limited space available in such a small screen (among other things). The simpler user interface allowed the user to focus.</p>
<p>Android has gone through the same transition over the years, from Cupcake yo KitKat.</p>
<p><strong>The Changing Desktop</strong></p>
<p>In some ways, this didn&#8217;t start with iPhone and Android. For example, for years many graphics and photo-editing applications have used a dark theme so that the application&#8217;s interface fades into the background helping the user focus on their content.</p>
<p><a href="http://www.xojo.com/blog/en/assets_c/2014/07/Photoshop-462.php"><img decoding="async" class="mt-image-center" style="text-align: center; display: block; margin: 0px auto 20px; width: 400px;" title="photoshop_screenshot.png" src="https://blog.xojo.com/wp-content/uploads/2014/07/photoshop_screenshot.pngt1466486449161ampwidth400" sizes="(max-width: 400px) 100vw, 400px" alt="photoshop_screenshot.png" width="400" data-constrained="true" /></a> Microsoft Windows 8 offered a radically different user interface. While the change has certainly been contraversial, it&#8217;s clearly meant to simplify the desktop user experience. Microsoft&#8217;s motivation was to provide a single user experience for desktop and mobile. It&#8217;s clear now that this was not a complete success and it seems they are going to make a new attempt with Windows 9.</p>
<p>Now Apple, with the upcoming release of OS X 10.10 Yosemite, is simplifying the user interface as well. You can click to enlarge the picture below.</p>
<p><a href="http://www.xojo.com/blog/en/assets_c/2014/07/OS%20X%20Yosemite-477.php"><img loading="lazy" decoding="async" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" src="https://blog.xojo.com/wp-content/uploads/2014/07/os20x20yosemite-thumb-400x234-477.jpgt1466486449161ampwidth504ampheight295" sizes="auto, (max-width: 504px) 100vw, 504px" alt="OS X Yosemite.jpg" width="504" height="295" /></a></p>
<p>But in Apple&#8217;s case, I believe the motivation is more about simplifying for two reasons:</p>
<p>1) The simpler the visual aspects are, the more the user can focus on their content. Apple is not removing functionality. The change is more about how they render the user interface itself. There are fewer lines and fewer colors.</p>
<p>2) While Apple firmly (and rightly, IMHO) believes that you can&#8217;t have the exact same user experience on a mobile device as a desktop, there are visual cues that can be shared which make it easier for the user to switch between devices- icons for sharing, etc. Switching between desktop and mobile devices is a behavior that is very common and only becoming more so.</p>
<h4>Coming Full Circle</h4>
<p>In some ways we have come full circle. We started with simple user interfaces that were skeuomorphic and became even more so over time. At the time, they had to be because the user needed to relate the user interface to the real world. The Graphical User Interface has been around long enough now that it no longer needs to be skeuomorphic. Today, user interfaces need to make sense to users who already have experience with a graphical user interface. The simplified user interface makes the user experience more friendly and allows the user to stay more focused on what they are trying to accomplish. In subtle ways it increases productivity which, after all, is why we use computing devices in the first place.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>The iOS 7 UI Controversy</title>
		<link>https://blog.xojo.com/2013/06/18/the-ios-7-ui-controversy/</link>
		
		<dc:creator><![CDATA[Geoff Perlman]]></dc:creator>
		<pubDate>Tue, 18 Jun 2013 00:00:00 +0000</pubDate>
				<category><![CDATA[iOS]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[UI]]></category>
		<guid isPermaLink="false">http://blogtemp.xojo.com/2013/06/18/the-ios-7-ui-controversy/</guid>

					<description><![CDATA[Unless you have been living under a rock for the past week, you know that Apple unvieled iOS 7 and its new user interface coming this fall to an iOS device near you. ]]></description>
										<content:encoded><![CDATA[<p>Unless you have been living under a rock for the past week, you know that Apple unvieled <a title="iOS 7 Screenshots" href="http://www.apple.com/ios/ios7/" target="_blank" rel="noopener">iOS 7</a> and its new user interface coming this fall to an iOS device near you. While there are some great new features, like the engine in a car, it&#8217;s not the first thing people notice. Most car shoppers are looking at the color of the paint, the sleekness of the design, the look of the interior and dashboard, etc. In other words, they look at the cars&#8217; UI.</p>
<p>The new UI in iOS 7 is the most controversial thing about it by far. I&#8217;ll admit that when I first saw it, I thought they were changing it just to change it. I thought they hadn&#8217;t put enough thought into the reasons why or they were just bending to the pressure of change for change&#8217;s sake. In my role at <a title="Xojo Website" href="http://www.xojo.com" target="_blank" rel="noopener">Xojo</a>, I think at a lot about UI design. Before long, I realized that of course Apple put a lot of thought into it. That&#8217;s what Apple does. It&#8217;s their culture. So why were they going with this new, simpler, non-skeumorphic design?</p>
<p><span id="more-32"></span></p>
<p><span style="line-height: 1.62;">Then it hit me. First, skeumorphic makes less and less sense. When I was a kid, phones had handsets like one in the icon for the Phone app. Calenders were something you purchased and hung on your wall. Your camera was something that you used to take pictures and that&#8217;s it. It did nothing else. Skeumorphic makes sense when you need to connect a real world object with its digital counterpart. But the younger you are, the less these skeumorphic designs make sense.</span></p>
<p>My daughter is 12 years old and has an iPhone. We have never had a home phone that she can remember. Her iPhone is of course her phone but it&#8217;s also her calendar, her camera, her notepad and her TV. It doesn&#8217;t replace these things. It <strong>is</strong> these things. Over time, fewer and fewer people will recognize the skeumorphic designs because those real world objects are not part of their world. Thus the value of skeumorphic design decreases.</p>
<p>The other day, I showed my daughter and my 10 year old son the new iOS 7 user interface (from Apple&#8217;s website linked to earlier in this post). I asked each of them if they preferred the new look, the one they currently had (iOS 6) or thought that one wasn&#8217;t better than the other. They both preferred iOS 7. When I asked them why (independently so they would not bias each other), they both said the same thing, &#8220;Because it&#8217;s cooler.&#8221; I have no doubt that I would get a similar response from most iOS users 25 and younger.</p>
<p>There are no doubt many important reasons Apple identified for refreshing the iOS user interface. We will probably never know them all. But &#8220;cool&#8221; is important. Cool is especially important to young people who buy a lot of iOS devices and their brand loyalty to the Apple ecosystem is therefore important to Apple.<!-- end HubSpot Call-to-Action Code --></p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
