<?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>embedded Archives | DMC, Inc.</title>
	<atom:link href="https://static.dmcinfo.com/blog/tag/embedded/feed/index.xml" rel="self" type="application/rss+xml" />
	<link></link>
	<description></description>
	<lastBuildDate>Tue, 04 Aug 2026 21:07:05 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.2</generator>

<image>
	<url>https://static.dmcinfo.com/wp-content/uploads/2025/04/site-icon-150x150.png</url>
	<title>embedded Archives | DMC, Inc.</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>LVGL for International GUI Design</title>
		<link>https://static.dmcinfo.com/blog/17764/lvgl-for-international-gui-design/</link>
		
		<dc:creator><![CDATA[Ben Dyer]]></dc:creator>
		<pubDate>Wed, 01 Mar 2023 10:12:27 +0000</pubDate>
				<category><![CDATA[Embedded Development & Programming]]></category>
		<category><![CDATA[User Interface Design]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[embedded]]></category>
		<category><![CDATA[i18n]]></category>
		<category><![CDATA[internationalization]]></category>
		<category><![CDATA[LVGL]]></category>
		<category><![CDATA[microcontroller]]></category>
		<category><![CDATA[multi-language]]></category>
		<category><![CDATA[user interface]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/17764/lvgl-for-international-gui-design/</guid>

					<description><![CDATA[<p>Creating a high-quality user interface that can run on embedded systems is a challenging task, and that’s doubly (or perhaps triply) true if it’s intended for an international user base. As with any difficult job, however, it becomes much more manageable with the right tools. Read on to learn the basics of one such tool, [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/17764/lvgl-for-international-gui-design/">LVGL for International GUI Design</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><!-- Injected  Highlight.js Code --><script type="text/javascript" src="/Providers/HtmlEditorProviders/CKEditor/plugins/codesnippet/lib/highlight/highlight.pack.js?ver=1790905719"></script><link type="text/css" rel="stylesheet" href="/Providers/HtmlEditorProviders/CKEditor/plugins/codesnippet/lib/highlight/styles/default.css?ver=1790905719"/><script type="text/javascript">window.onload = function() {var aCodes = document.getElementsByTagName('pre');for (var i=0; i < aCodes.length;i++){hljs.highlightBlock(aCodes[i]);} };</script></p>


<p class="wp-block-paragraph">Creating a high-quality user interface that can run on embedded systems is a challenging task, and that’s doubly (or perhaps triply) true if it’s intended for an international user base.</p>



<p class="wp-block-paragraph">As with any difficult job, however, it becomes much more manageable with the right tools. Read on to learn the basics of one such tool, LVGL, and its associated utilities.</p>



<h2 id="h-getting-started-with-lvgl" class="wp-block-heading">Getting Started with LVGL</h2>



<p class="wp-block-paragraph">In order to develop with LVGL, it will need&nbsp;to be ported to your platform of choice.</p>



<p class="wp-block-paragraph">First, pull the latest release of LVGL into a project configured for your target and create “lv_conf.h” from the included template. This file contains a variety of parameters for tweaking the library’s behavior, but they can be left at their default values for now. Add a call to <strong>lv_init</strong>&nbsp;to your program, ensuring it’s in a location where it will occur before any other LVGL functions are called.</p>



<p class="wp-block-paragraph">Next, you will need to define drivers for the display showing your UI and any input devices used to interact with it. The specifics of these drivers will vary greatly from project to project, and LVGL already has excellent documentation on porting, so only the general structure will be covered here.</p>



<p class="wp-block-paragraph">In simple cases, you will only need to allocate some memory to act as a draw buffer, define the resolution of the display, and implement a function to send the information LVGL places into the draw buffer to your screen.&nbsp;The example below shows a basic setup, but additional configuration options exist to implement things like double-buffering or screen rotation.</p>



<p class="wp-block-paragraph"></p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>static lv_color_t draw_buffer&#91;SCREEN_HOR_RES * SCREEN_VER_RES / 10&#93;;
static lv_disp_drv_t disp_drv;
static lv_disp_draw_buf_t disp_buf;

void flush_buffer_callback(lv_disp_drv_t* disp_drv, const lv_area_t* area, lv_color_t* color_p);

lv_disp_t* lvgl_display_port_init()
{
    //configure any platform specific peripherals here

    //set up draw buffer
    lv_disp_draw_buf_init(&amp;disp_buf, draw_buffer, NULL, SCREEN_HOR_RES * SCREEN_VER_RES / 10);

    //initialize display driver
    lv_disp_drv_init(&amp;disp_drv);

    //configure display driver
    disp_drv.draw_buf = &amp;disp_buf;
    disp_drv.hor_res = SCREEN_HOR_RES;
    disp_drv.ver_res = SCREEN_VER_RES;
    disp_drv.flush_cb = flush_buffer_callback;

    //set optional fields to customize display driver here
   
    //finalize driver setup
    return lv_disp_drv_register(&amp;disp_drv);
}

void flush_buffer_callback(lv_disp_drv_t* disp_drv, const lv_area_t* area, lv_color_t* color_p)
{
    /* copy pixels from 'color_p' to the area of the screen described by 'area' */
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">static</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">lv_color_t</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">draw_buffer</span><span style="color: #D4D4D4">&#91;SCREEN_HOR_RES * SCREEN_VER_RES / </span><span style="color: #B5CEA8">10</span><span style="color: #D4D4D4">&#93;;</span></span>
<span class="line"><span style="color: #569CD6">static</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">lv_disp_drv_t</span><span style="color: #D4D4D4"> disp_drv;</span></span>
<span class="line"><span style="color: #569CD6">static</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">lv_disp_draw_buf_t</span><span style="color: #D4D4D4"> disp_buf;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">flush_buffer_callback</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">lv_disp_drv_t</span><span style="color: #D4D4D4">* </span><span style="color: #9CDCFE">disp_drv</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">lv_area_t</span><span style="color: #D4D4D4">* </span><span style="color: #9CDCFE">area</span><span style="color: #D4D4D4">, </span><span style="color: #4EC9B0">lv_color_t</span><span style="color: #D4D4D4">* </span><span style="color: #9CDCFE">color_p</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4EC9B0">lv_disp_t</span><span style="color: #D4D4D4">* </span><span style="color: #DCDCAA">lvgl_display_port_init</span><span style="color: #D4D4D4">()</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">//configure any platform specific peripherals here</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">//set up draw buffer</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">lv_disp_draw_buf_init</span><span style="color: #D4D4D4">(&amp;disp_buf, draw_buffer, </span><span style="color: #569CD6">NULL</span><span style="color: #D4D4D4">, SCREEN_HOR_RES * SCREEN_VER_RES / </span><span style="color: #B5CEA8">10</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">//initialize display driver</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">lv_disp_drv_init</span><span style="color: #D4D4D4">(&amp;disp_drv);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">//configure display driver</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">disp_drv</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">draw_buf</span><span style="color: #D4D4D4"> = &amp;disp_buf;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">disp_drv</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">hor_res</span><span style="color: #D4D4D4"> = SCREEN_HOR_RES;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">disp_drv</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">ver_res</span><span style="color: #D4D4D4"> = SCREEN_VER_RES;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">disp_drv</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">flush_cb</span><span style="color: #D4D4D4"> = flush_buffer_callback;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">//set optional fields to customize display driver here</span></span>
<span class="line"><span style="color: #D4D4D4">   </span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">//finalize driver setup</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">lv_disp_drv_register</span><span style="color: #D4D4D4">(&amp;disp_drv);</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">flush_buffer_callback</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">lv_disp_drv_t</span><span style="color: #D4D4D4">* </span><span style="color: #9CDCFE">disp_drv</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">lv_area_t</span><span style="color: #D4D4D4">* </span><span style="color: #9CDCFE">area</span><span style="color: #D4D4D4">, </span><span style="color: #4EC9B0">lv_color_t</span><span style="color: #D4D4D4">* </span><span style="color: #9CDCFE">color_p</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #6A9955">    /* copy pixels from &apos;color_p&apos; to the area of the screen described by &apos;area&apos; */</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>


<pre><code class="language-cpp">
</code></pre>


<p class="wp-block-paragraph"><span id="cke_bm_275C" style="display: none;">&nbsp;</span></p>



<p class="wp-block-paragraph">Configuring an input device follows a similar process. Use <strong>lv_indev_drv_init</strong>&nbsp;to set up the driver, define its type,&nbsp;attach a function for reading its value, and register it using <strong>lv_indev_drv_register</strong>.<span id="cke_bm_399C" style="display: none;">&nbsp;</span></p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>static lv_indev_drv_t indev_drv;
void input_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data);

void lvgl_indev_port_init(void);
{
    //configure any necessary platform specific peripherals here

    //set up input device driver
    lv_indev_drv_init(&amp;indev_drv);

    //configure input device driver
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = input_read;
    
    //finalize driver setup
    lv_indev_t* touch_indev = lv_indev_drv_register(&amp;indev_drv);
}

void input_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data)
{
    /* Read location from input device (i.e. last touch location on a touchscreen) */

    /* Read state from input device (i.e. is a touchscreen currently being touched) */

    /* Store current location (x, y) and state (pressed, released) in 'data' */
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">static</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">lv_indev_drv_t</span><span style="color: #D4D4D4"> indev_drv;</span></span>
<span class="line"><span style="color: #569CD6">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">input_read</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">lv_indev_drv_t</span><span style="color: #D4D4D4"> *</span><span style="color: #9CDCFE">indev_drv</span><span style="color: #D4D4D4">, </span><span style="color: #4EC9B0">lv_indev_data_t</span><span style="color: #D4D4D4"> *</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">lvgl_indev_port_init</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">void</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">//configure any necessary platform specific peripherals here</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">//set up input device driver</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">lv_indev_drv_init</span><span style="color: #D4D4D4">(&amp;indev_drv);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">//configure input device driver</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">indev_drv</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">type</span><span style="color: #D4D4D4"> = LV_INDEV_TYPE_POINTER;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">indev_drv</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">read_cb</span><span style="color: #D4D4D4"> = input_read;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">//finalize driver setup</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #4EC9B0">lv_indev_t</span><span style="color: #D4D4D4">* touch_indev = </span><span style="color: #DCDCAA">lv_indev_drv_register</span><span style="color: #D4D4D4">(&amp;indev_drv);</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">input_read</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">lv_indev_drv_t</span><span style="color: #D4D4D4"> *</span><span style="color: #9CDCFE">indev_drv</span><span style="color: #D4D4D4">, </span><span style="color: #4EC9B0">lv_indev_data_t</span><span style="color: #D4D4D4"> *</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #6A9955">    /* Read location from input device (i.e. last touch location on a touchscreen) */</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">    /* Read state from input device (i.e. is a touchscreen currently being touched) */</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">    /* Store current location (x, y) and state (pressed, released) in &apos;data&apos; */</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">&nbsp;</p>



<p class="wp-block-paragraph">With the display and input device drivers implemented, the final step is to create an environment for LVGL to run in. In simple applications, this might be an infinite loop at the end of main function, while more complex applications may utilize an RTOS (real-time operating system) and give LVGL its own thread. Many approaches will work as long as <strong>lv_tick_inc</strong>&nbsp;and <strong>lv_timer_handler</strong>&nbsp;are called periodically, with <strong>lv_tick_inc</strong>&nbsp;occurring at least as frequently as <strong>lv_timer_handler</strong>.</p>



<p class="wp-block-paragraph">Note that LVGL functions are not inherently thread-safe or interrupt-safe; if using interrupts or an RTOS, utilize synchronization tools like mutexes or take care to limit calls to LVGL such that they cannot overlap.</p>



<p class="wp-block-paragraph">With all of the above in place, LVGL should be ready to use.</p>



<h2 id="h-internationalization-tools" class="wp-block-heading">Internationalization Tools</h2>



<p class="wp-block-paragraph">In addition to the base library, LVGL has several supplementary tools to aid in development. When creating a UI for an international user base, two such tools stand out as essential:&nbsp;LVGL’s internationalization library, which provides&nbsp;simple tools for text substitution, and LVGL's&nbsp;font converter, which allows a developer to parse glyphs from several fonts into a single file for use with LVGL.</p>



<p class="wp-block-paragraph"><span style="font-family:arial;">For both of these tools, you will need node.js (at least version 14) and the&nbsp;package manager it comes bundled with (called npm). You can</span> <span style="font-family:arial;"><a href="https://nodejs.org/en/download/" type="link" id="https://nodejs.org/en/download/">download them</a>&nbsp;here. Sticking with the default installation options will work for the tools covered here.</span></p>



<p class="wp-block-paragraph"><span style="font-family:arial;">After installing, ensure that both node.js and npm are added to your system PATH. Open command prompt, and install the font converter with </span><strong>npm i lv_font_conv -g</strong><span style="font-family:arial;"> and the internationalization library with <strong>npm i lv_i18n -g</strong> Both tools should now be usable in your project.</span></p>



<h2 id="h-lv-i18n" class="wp-block-heading">lv_i18n</h2>



<p class="wp-block-paragraph"><span style="font-family:arial;">The process described below was adapted from the setup instructions provided with lv_i18n&nbsp;with notes from personal experience. For the original instructions, see the <a href="https://github.com/lvgl/lv_i18n" rel="no follow" target="_blank">lv_i18n github</a>.</span></p>



<p class="wp-block-paragraph">Start off with a simple example, and wrap any text which will be translated in <strong>_( )</strong>. For strings containing plurals, <strong>_p( )</strong>&nbsp;can be used instead to support languages with different pluralization rules from your base language. Include “lv_i18n.h” (this file doesn’t exist yet as&nbsp;it will be generated by the tool later) and, after initializing LVGL, call <code>lv_i18n_init</code>&nbsp;and <code>lv_i18n_set_locale</code>. The locale can be set to any language that you plan to support, and it can be changed any time that it’s safe to call an LVGL API function.</p>



<p class="wp-block-paragraph"><span style="font-family:arial;">Next, create a folder to store translations, add a .yml file for each language you plan to support (including the language you are developing in), and title the files&nbsp;with <a href="https://www.andiamo.co.uk/resources/iso-language-codes/" rel="no follow" target="_blank">language codes</a>. Write the language code, followed by a colon, into the first line of each file (ex: Portuguese would have a file called “pt.yml”, and it’s first line would be “pt:”). Once your example is done, from a command prompt in your project, run the following (without angle brackets):</span></p>



<p class="wp-block-paragraph"><code>lv_i18n extract -s ‘&lt;path to your source files&gt;/*.+(c|cpp|h|hpp)’ -t ‘&lt;path to your yml translations&gt;/*.yml’ </code></p>



<p class="wp-block-paragraph"><span style="font-family:arial;">This will populate the translation files with a list of every string from your project wrapped in <code>_( )</code>. Next to each, add its translation in the language corresponding to the yml file it’s in. To implement these translations, run the following:</span><br>
<br>
<code>lv_i18n compile -t ‘&lt;path to your yml translations&gt;/*.yml’ -o ‘&lt;path where you want lv_i18n.h to go&gt;’</code><br>
<br>
<span style="font-family:arial;">The output location of this command will receive lv_i18n.h and lv_i18n.c, which will contain all of your translations in a form that the tool can reference. It will need to be accessible by any file that calls <code>_( )</code>, so set up its location accordingly. </span></p>



<p class="wp-block-paragraph"><span style="font-family:arial;">Now, your example should be ready to run. Any time that code containing a string wrapped in <code>_( )</code> executes, the current locale will be checked and the string will be substituted for its translation in that locale. This is a simple, literal substitution, so anything referencing the string will be affected, not just LVGL functions. Additionally, if new text is added, you will need to run <code>lv_i18n extract</code> and <code>lv_i18n compile</code> again.</span></p>



<h2 id="h-lv-font-conv" class="wp-block-heading">lv_font_conv</h2>



<p class="wp-block-paragraph"><span style="font-family:arial;">If one of your&nbsp;languages uses&nbsp;a script other than the Latin alphabet, you may notice missing characters when its translation is&nbsp;displayed. This is where the font converter comes in. Most fonts don’t describe a glyph for every Unicode character, so you will need to either find one that has all the characters you need&nbsp;or create one by splicing together a few fonts. </span></p>



<p class="wp-block-paragraph"><span style="font-family:arial;">First, prepare a list of characters needed, or ranges of characters. Even if you have a font which contains all the characters needed, it’s likely that it also contains many that you don’t, and fonts take up a lot of space (especially physically larger ones; by default, LVGL stores them as byte arrays, and more pixels means more bytes). </span></p>



<p class="wp-block-paragraph">Next, parse this list into a font converter call. Broadly, calls to the font converter are structured as a sequential list of font files, which characters to take from them, and then a few parameters to customize the output. Supply a path to the font file with <code>--font</code>, specify which characters to include from it with <code>--range</code>&nbsp;or <code>--symbols</code>, and repeat for each font to be included.</p>



<p class="wp-block-paragraph">When adding characters, <code>--symbols</code>&nbsp;accepts a list of characters. Duplicates are ignored, so you can freely copy and paste everything from one language’s translation into this argument, but be careful to remove any spaces as they may be treated as the end of the argument. <code>--range</code>&nbsp;accepts a single Unicode value or a contiguous range of Unicode values. See <a href="https://jrgraphix.net/research/unicode.php" rel="no follow" target="_blank">Unicode ranges</a> for reference. You can add as many <code>--range</code>&nbsp;and <code>--symbols</code>&nbsp;arguments as needed. Next, add the font size to generate with <code>--size</code>, the format with <code>--format</code>, the level of detail with <code>--bpp</code>, and a file path to output to with <code>-o</code>. The <a href="https://github.com/lvgl/lv_font_conv" rel="no follow" target="_blank">font converter github page</a> has more details on each of these parameters.</p>



<p class="wp-block-paragraph">&nbsp;<span style="font-family:arial;">Altogether, a call might look like the following:</span></p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Bash</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly> lv_font_conv --font ARIALUNI.TTF

  --range 0x0000-0x017F

  --range 0x0400-0x04FF

  --symbols КАСБОЙ

 --font NotoSansArabic-Regulat.ttf

  --range 0x0600-0x06FF

  --range 0xFE70-0xFEFF

 --size 10 --format lvgl --bpp 3 -o examplefont.c</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">lv_font_conv</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">--font</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">ARIALUNI.TTF</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">--range</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">0x0000</span><span style="color: #CE9178">-0x017F</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">--range</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">0x0400</span><span style="color: #CE9178">-0x04FF</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">--symbols</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">КАСБОЙ</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">--font</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">NotoSansArabic-Regulat.ttf</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">--range</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">0x0600</span><span style="color: #CE9178">-0x06FF</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">--range</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">0xFE70</span><span style="color: #CE9178">-0xFEFF</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">--size</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">10</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">--format</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">lvgl</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">--bpp</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">3</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-o</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">examplefont.c</span></span></code></pre></div>



<pre class="wp-block-code"><code> </code></pre>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"><span style="font-family:arial;">Note that newlines and indentation are included for clarity, the only separator should be spaces since this is invoked from a command line. To that end, it’s helpful to store arguments in a text file, then parse them into calls in a script with something like bash’s <code>mapfile</code>&nbsp;command.</span></p>



<p class="wp-block-paragraph">Once a font has been generated, it can be included in the project, declared with <code>LV_FONT_DECLARE</code>, and used the same as LVGL’s default fonts.</p>



<h2 id="h-common-challenges" class="wp-block-heading">Common Challenges</h2>



<p class="wp-block-paragraph">What follows is a collection of some common challenges one might encounter when creating internationalized UIs, and some tips as to how they can be handled with&nbsp;the tools discussed here.</p>



<p class="wp-block-paragraph"><u><strong>Base Direction</strong></u></p>



<p class="wp-block-paragraph">Languages vary in their base directions; English, for example, is a left-to-right (LTR) language, while languages using the Arabic script are right-to-left languages (RTL). LVGL has some built-in handling for different base directions, namely the <code>base_dir</code>&nbsp;style property.</p>



<p class="wp-block-paragraph">When creating an object, it can be given a base direction with <code>lv_obj_set_style_base_dir</code>, or attaching a style with the property already set (by <code>lv_style_set_base_dir</code>). This will work in most cases, but, with strings containing both LTR and RTL languages, you may need to specify text direction manually. For this, one can use Unicode directional indicators. Including the following in your project will allow you to change direction within a string.</p>



<p class="wp-block-paragraph"><code>#define LRI "\xE2\x81\xA6"</code></p>



<p class="wp-block-paragraph"><code>#define RLI "\xE2\x81\xA7"</code></p>



<p class="wp-block-paragraph"><code>#define PDI "\xE2\x81\xA9"</code></p>



<p class="wp-block-paragraph">LRI indicates left-to-right, RLI the opposite, and PDI (pop directional indicator) undoes the most recent indicator. Wrapping chunks of text in LRI/RLI … PDI can be thought of as splitting the overall string into substrings, with the base direction of the overall string governing the order these substrings will appear. As an example, if the following string were to be placed in a label with RTL base direction:</p>



<p class="wp-block-paragraph">“&lt;LRI&gt;123&lt;PDI&gt; &lt;RLI&gt;456&lt;PDI&gt; &lt;LRI&gt;789&lt;PDI&gt;”</p>



<p class="wp-block-paragraph">(note: angle brackets included for clarity), it would appear on screen as</p>



<p class="wp-block-paragraph">“789 654 123”.</p>



<p class="wp-block-paragraph">Note also that LVGL may output warnings for missing glyph descriptions when rendering strings containing these characters. They are zero-width characters and function correctly regardless of whether they are included in the font, so these warnings can be safely ignored&nbsp;or suppressed in lv_conf.h (though missing glyph warnings are very helpful when working with custom fonts).</p>



<p class="wp-block-paragraph"><u><strong>Information Density</strong></u></p>



<p class="wp-block-paragraph">Languages vary in information density; three Chinese characters might convey the same information as twenty Latin ones in English or thirty in Spanish. As such, it’s helpful to leave extra space in screen layouts for languages less dense than the one being used for development.</p>



<p class="wp-block-paragraph">When this isn't possible, however, one can also use LVGL’s long text handling. Calling <code>lv_label_set_long_mode</code>&nbsp;will allow the developer to specify whether a label with text that does not fit in its width scrolls, wraps, or is cut off (optionally ending the displayed text with “…”) . Make sure to set the width of the label <u>after</u> calling this function.</p>



<p class="wp-block-paragraph">In cases where built-in long modes are not desirable, another option is to decrease font size. Using <code>lv_txt_get_size</code>&nbsp;to check whether a string will fit in a space with a given font, it’s possible to implement automatic font scaling&nbsp;(though the exact process will vary greatly from UI to UI depending on the desired behavior).</p>



<p class="wp-block-paragraph"><u><strong>Inserting Variables into Translated Text</strong></u></p>



<p class="wp-block-paragraph">One common use of text in a UI is to provide context for numerical information, which is complicated by the fact that translations need to be compiled beforehand. Thankfully, there’s a simple solution. As mentioned before, lv_i18n’s translation function&nbsp;<code>_( )</code> is a simple, direct replacement. This means that the translated string can be used with basic C text functions, namely <code>snprintf</code>. Including “%s” (or other format codes) in both the initial string and its translations will allow values to be inserted into the string by code after translation. When using this method, take care to allocate enough space in the buffer passed to <code>snprintf</code>&nbsp;for your longest translation.</p>



<p class="wp-block-paragraph">When a string contains multiple variable values, they can appear in different orders from language to language. This can be solved with either clever translation to keep fields in the same order, or by tracking which language is active and supplying arguments to <code>sprintf</code>&nbsp;in the corresponding order.</p>



<p class="wp-block-paragraph"><u><strong>Duplicate words</strong></u></p>



<p class="wp-block-paragraph">Languages often have words that&nbsp;mean several different things. As an example, an English UI might include the string “set” in multiple places, some using the word as a verb, others as a noun. These words don’t necessarily line up between languages, so the string “set” would likely need two translations in other languages. lv_i18n can only attach one translation to each original string per language, so this may initially seem like a significant issue, but the tool is perfectly capable of handling these situations.</p>



<p class="wp-block-paragraph">lv_i18n creates a lookup table for each language, mapping strings to other strings. The initial, untranslated strings scraped from your file are really just IDs to search translations by, and you can supply corresponding “translations” for them in your base locale (development language) just like any other language.</p>



<p class="wp-block-paragraph">Returning to the previous example with the word “set”, you can change the strings in your code to “set (v)” and “set (n)” and re-run <code>lv_i18n extract</code>. In the yml files belonging to other languages, fill in the translation for "set" as a noun next to “set (n)” and "set" as a verb next to “set (v)”. In “en.yml”, just place the word “set” next to both.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/duplicate_word_example.png" alt="Translation files implementing duplicate words"/></figure>



<p class="wp-block-paragraph">Re-run <code>lv_i18n compile</code>. Running the program in English, you should still see “set” everywhere, but changing the language will now show different translations for different uses of “set”.</p>



<p class="wp-block-paragraph"><strong>Learn More about DMC's <a href="/services/embedded-development-and-embedded-programming/embedded-user-interface-design">Embedded User Interface Design</a> services and <a href="/contact">contact us</a> today for your next project.</strong></p>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://static.dmcinfo.com/blog/17764/lvgl-for-international-gui-design/">LVGL for International GUI Design</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Getting Started with WinCC OA: Part 12 &#8211; Modules and Embedded Modules</title>
		<link>https://static.dmcinfo.com/blog/18628/getting-started-with-wincc-oa-part-12-modules-and-embedded-modules/</link>
		
		<dc:creator><![CDATA[Nick Leisle]]></dc:creator>
		<pubDate>Fri, 25 Mar 2022 09:49:21 +0000</pubDate>
				<category><![CDATA[HMI and SCADA]]></category>
		<category><![CDATA[dashboard]]></category>
		<category><![CDATA[embedded]]></category>
		<category><![CDATA[getting started]]></category>
		<category><![CDATA[ModuleName]]></category>
		<category><![CDATA[modules]]></category>
		<category><![CDATA[WinCC OA]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/18628/getting-started-with-wincc-oa-part-12-modules-and-embedded-modules/</guid>

					<description><![CDATA[<p>Welcome back to “Getting Started with WinCC OA!” If you aren’t familiar with the series’ previous topics, it’s recommended that you read the respective installments before proceeding: What is a Module? As noted in Part 11 of “Getting Started with WinCC OA”: “Modules represent their own program window, meaning that the child panel is disjointed [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/18628/getting-started-with-wincc-oa-part-12-modules-and-embedded-modules/">Getting Started with WinCC OA: Part 12 &#8211; Modules and Embedded Modules</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Welcome back to “Getting Started with WinCC OA!” If you aren’t familiar with the series’ previous topics, it’s recommended that you read the respective installments before proceeding:</p>



<ul class="wp-block-list">
<li><a href="/latest-thinking/blog/id/9870/getting-started-with-wincc-oa-part-1--creating-opening-a-project" target="_blank">Part 1: Creating and Opening a Project</a></li>



<li><a href="/latest-thinking/blog/id/9871/getting-started-with-wincc-oa-part-2--folder-structure-gedi-layout" target="_blank">Part 2: Folder Structure and Gedi Layout</a></li>



<li><a href="/latest-thinking/blog/id/9884/getting-started-with-wincc-oa-part-3--panels-the-basics" target="_blank">Part 3: Panels | The Basics</a></li>



<li><a href="/latest-thinking/blog/id/9893/getting-started-with-wincc-oa-part-4--panel-scripting-environments-and-quicktest" target="_blank">Part 4: Panel Scripting Environments and QuickTest</a></li>



<li><a href="/latest-thinking/blog/id/9906/getting-started-with-wincc-oa-part-5--scripting-syntax" target="_blank">Part 5: Scripting Syntax</a></li>



<li><a href="/latest-thinking/blog/id/9921/getting-started-with-wincc-oa-part-6--para-overview-and-datapoint-creation" target="_blank">Part 6: Para Overview and Datapoint Creation</a></li>



<li><a href="/latest-thinking/blog/id/9944/getting-started-with-wincc-oa-part-7--interacting-with-datapoints-via-scripting" target="_blank">Part 7: Interacting with Datapoints via Scripting</a></li>



<li><a href="/latest-thinking/blog/id/10014/getting-started-with-wincc-oa-part-8--libraries" target="_blank">Part 8: Libraries</a></li>



<li><a href="https://static.dmcinfo.com/latest-thinking/blog/id/10093/getting-started-with-wincc-oa-part-9--color-database-and-high-performance-best-practices" target="_blank">Part 9: Color Database &amp; High-Performance Best Practices</a></li>



<li><a href="https://static.dmcinfo.com/latest-thinking/blog/id/10138/getting-started-with-wincc-oa-part-10--panel-nesting-and-parameters" target="_blank">Part 10: Panels | Panel Nesting and $-Parameters</a></li>



<li><a href="https://static.dmcinfo.com/latest-thinking/blog/id/10184/getting-started-with-wincc-oa-part-11--panels-child-panels-popups" target="_blank">Part 11: Panels | Child Panels (Popups)</a></li>
</ul>



<h2 id="h-what-is-a-module" class="wp-block-heading">What is a Module?</h2>



<p class="wp-block-paragraph">As noted in <a href="https://static.dmcinfo.com/latest-thinking/blog/id/10184/getting-started-with-wincc-oa-part-11--panels-child-panels-popups">Part 11</a> of “Getting Started with WinCC OA”:</p>



<p class="wp-block-paragraph">“Modules represent their own program window, meaning that the child panel is disjointed from the calling panel and its respective calling module. If the calling panel is changed/closed, the child panel/module will remain opened.”</p>



<p class="wp-block-paragraph">Modules can be hidden, minimized, maximized, zoomed, and much more. While these topics aren’t pertinent to get started with WinCC OA, they’re still helpful to note. With that said, we’ll now focus on embedded modules and their applications.</p>



<h2 id="h-embedded-modules" class="wp-block-heading">Embedded Modules</h2>



<p class="wp-block-paragraph">Like child panels, embedded modules are used to display sub-panels in conjunction with a main panel. On the contrary, while&nbsp;a child panel opens in front of the calling panel, an embedded module exists within an allocated space on the main panel itself.</p>



<p class="wp-block-paragraph">These embedded modules are helpful for presenting dashboards, portioning out screen real estate, displaying alarm buffers, and more.</p>



<p class="wp-block-paragraph">For example, one of the default templates located in the <u>base</u>&nbsp;project (Panels/para/PanelTopology/templates/TEMPLATE3/basePanel_1024_768) uses embedded modules to divide the screen into three functional areas. The template contains three primary embedded modules with names that dictate their general purposes:</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Picture1_Sized.png" alt="Primary embedded modules"/></figure>



<p class="wp-block-paragraph">While we won’t go into too much detail on templates here, it’s important to note that&nbsp;when implemented during runtime, the embedded modules allocate a certain quantity of real estate and present certain sub-panels on the overall display.</p>



<ul class="wp-block-list">
<li><strong>mainModule:&nbsp;</strong>Displays the general user-defined screens</li>



<li><strong>naviModule:&nbsp;</strong>Displays the UI&#8217;s navigation controls</li>



<li><strong>infoModule:&nbsp;</strong>Displays pertinent information (alarms buffer, date/time, user, etc.)</li>
</ul>



<p class="wp-block-paragraph">During runtime, the naviModule and infoModule continuously display their respective content while the mainModule displays the main panels, as defined in the project’s Panel Topology (Panel Topology will be discussed in a later blog installment).</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Picture2_Getting_Started_With_WinCC_OA_Resized.png" alt="Panel Topography"/></figure>



<h2 id="h-embedded-module-functions" class="wp-block-heading">Embedded Module Functions</h2>



<p class="wp-block-paragraph">The most relevant embedded module functions are as follows:</p>



<ul class="wp-block-list">
<li><strong>RootPanelOnModule()</strong>

 
 
<ul class="wp-block-list">
<li>Opens a panel in a specified module.</li>



<li>Arguments include:
  
  
<ul class="wp-block-list">
<li>FileName – File within the “panels” folder to open.</li>



<li>PanelName – Name given to panel.</li>



<li>ModuleName
   
   
<ul class="wp-block-list">
<li>Name of module in which the panel will open.</li>
</ul>
</li>



<li>Parameters
   
   
<ul class="wp-block-list">
<li>Panel $-Parameters; see <a href="https://static.dmcinfo.com/latest-thinking/blog/id/10138/getting-started-with-wincc-oa-part-10--panel-nesting-and-parameters">Part 10</a> for information on $-Parameters and <a href="https://static.dmcinfo.com/latest-thinking/blog/id/10184/getting-started-with-wincc-oa-part-11--panels-child-panels-popups">Part 11</a> for how to pass them into panels from calling functions.</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>



<li><strong>PanelOffModule()</strong>
 
 
<ul class="wp-block-list">
<li>Closes the&nbsp;panel in a specified module.</li>



<li>Arguments include:
  
  
<ul class="wp-block-list">
<li>PanelName – Name of panel to close.</li>



<li>ModuleName – Name of module in which the specified panel is open.</li>
</ul>
</li>
</ul>
</li>



<li><strong>rootPanel()</strong>
 
 
<ul class="wp-block-list">
<li>Returns the name of the panel open in the given module.</li>



<li>Arguments include:
  
  
<ul class="wp-block-list">
<li>ModuleName – Name of the root panel open in the specified module.</li>
</ul>
</li>
</ul>
</li>
</ul>



<p class="wp-block-paragraph">Fortunately, embedded modules are relatively straightforward to work with. One item to note, however, is that the argument “ModuleName” for relevant functions pertains to the “ModuleName” property (located under the “Extended” properties tab) rather than the embedded module object’s “Name” (located under the “Standard” properties tab).</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Picture1_Edited.jpg" alt="Embedded Modules located under the Standard properties tab"/></figure>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Picture2-_Edited.png" alt="Embedded Modules located under the Standard properties tab"/></figure>



<p class="wp-block-paragraph">In addition to its explicit string value, the “ModuleName” can be referenced in scripting using the notation:</p>



<pre class="wp-block-code"><code>
&lt;object name&gt;.ModuleName
</code></pre>



<h2 id="h-example" class="wp-block-heading">Example</h2>



<p class="wp-block-paragraph">We’ll continue working with our evolving example from prior blogs to create a dashboard using embedded modules.</p>



<p class="wp-block-paragraph"><u>Better Naming Practices</u></p>



<p class="wp-block-paragraph">First, we’ll do a brief rename of our current panels/DPTs, since names like “TestPanel” and “ChildPanel” are not very descriptive. Please make the following panel changes:</p>



<ul class="wp-block-list">
<li><strong>Rename:</strong> ChildPanel.pnl → SetSpeedLimitPopup.pnl</li>



<li><strong>Rename: </strong>TestPanel.pnl → MotorInfoPanel.pnl</li>



<li><strong>Delete:</strong> ParentPanel.pnl (it will not be needed anymore)&nbsp;</li>
</ul>



<p class="wp-block-paragraph"><strong>Note:</strong> the “ChildPanel.pnl” string in the MotorInfoPanel’s “settingsButtonClicked()” function will need to be changed as well.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Picture3_Edited.png" alt="SetSpeedLimitPopup.pnl"/></figure>



<p class="wp-block-paragraph">In addition, we’ll change the DPT name “myDatapointType” to “Motor” by right-clicking on the DPT in Para and selecting “Edit Datapoint Type.”</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Picture4_Edited-900X1300.png" alt="Changing DPT name to Motor"/></figure>



<p class="wp-block-paragraph"><u>Dashboard</u></p>



<p class="wp-block-paragraph">Create a new panel called “main.pnl.” This will represent a main/home screen on a SCADA system. Please adjust your panel dimensions according to your screen resolution:</p>


<table style="width:100%">
<tbody>
<tr>
<th>Resolution</th>
<th>main.pnl size (x, y)</th>
</tr>
<tr>
<td>1024 x 768</td>
<td>856 x 604</td>
</tr>
<tr>
<td>1280 x 1024</td>
<td>1110 x 860</td>
</tr>
<tr>
<td>1600 x 1200</td>
<td>1430 x 1036</td>
</tr>
<tr>
<td>1680 x 1050</td>
<td>1510 x 918</td>
</tr>
<tr>
<td>1920 x 1200</td>
<td>1760 x 1036</td>
</tr>
</tbody>
</table>


<p class="wp-block-paragraph">At the top of the panel, we’ll add three objects with the following specified properties:</p>



<ul class="wp-block-list">
<li>A simple border for our “dashboard”:
 
 
<ul class="wp-block-list">
<li><strong>Object:</strong> Rectangle</li>



<li><strong>Name:</strong>&nbsp;“dashboardBackground”</li>
</ul>
</li>



<li>An embedded module frame for one of our dashboard items:
 
 
<ul class="wp-block-list">
<li><strong>Object:</strong>&nbsp;Embedded module</li>



<li><strong>Name:&nbsp;</strong>“motorInfoDashboard”</li>



<li><strong>ModuleName:&nbsp;</strong>“motorInfoEmbeddedModule”</li>



<li><strong>Size:&nbsp;</strong>Make identical to the “MotorInfoPanel.pnl” panel size</li>
</ul>
</li>



<li>An object to use in embedded module interaction:
 
 
<ul class="wp-block-list">
<li><strong>Object:&nbsp;</strong>Button</li>



<li><strong>Name:&nbsp;</strong>&#8220;nextMotorButton&#8221;</li>



<li><strong>Button text:&nbsp;</strong>&#8220;Next Motor&#8221;</li>
</ul>
</li>
</ul>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Picture5_Edited.png" alt="WinnCC OA Tutorial Panels"/></figure>



<p class="wp-block-paragraph">Within our panel’s scopeLib, we’ll have a few constants and variables defined.</p>



<p class="wp-block-paragraph"><strong>Constants:</strong></p>



<ul class="wp-block-list">
<li>MOTOR_INFO_PANEL = name of the motor info panel to open.</li>



<li>DP_MOTOR_LIST = list of all DPs of type “Motor”.</li>



<li>NUM_MOTORS = number of motor DPs.</li>
</ul>



<p class="wp-block-paragraph"><strong>Variables:</strong></p>



<ul class="wp-block-list">
<li>_dpCurrentMotorInfo – panel-scoped variable keeps track of the currently displayed motor DP.</li>
</ul>



<p class="wp-block-paragraph"><strong>Functions:</strong></p>



<ul class="wp-block-list">
<li>motorInfoDashboardInitialized() – called by the panel’s “Initialize” event; establishes the first motor displayed by calling “displayNextMorotInfoPanel()”.</li>



<li>nextMotorButtonClicked() – &nbsp;called by the “nextMotorButton” button’s “Ckicked” event; calls the “displayNextMotorInfoPanel()”.</li>



<li>displayNextMotorInfoPanel() – Displays the next motor DP defined in the DP_MOTOR_LIST into the motor info panel.</li>
</ul>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">HTML</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// Display the next motor in the Motor Info Dashboard
displayNextMotorInfoPanel()
{
    // Only attempt to display a dashboard if motors exist
    if (NUM_MOTORS > 0)
    {
        // Determine the next motor in the motor list
        int iNextMotorIndex =
            (dynContains(DP_MOTOR_LIST, _dpCurrentMotorInfo) % NUM_MOTORS) + 1;

        _dpCurrentMotorInfo = DP_MOTOR_LIST&#91;iNextMotorIndex&#93;;

        // Open the Motor Info panel for the selected motor
        RootPanelOnModule(
            MOTOR_INFO_PANEL,
            "MotorInfoPanel" + _dpCurrentMotorInfo,
            motorInfoDashboard.ModuleName,
            "$motorDpe:" + dpSubStr(_dpCurrentMotorInfo, DPSUB_DP)
        );
    }
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">// Display the next motor in the Motor Info Dashboard</span></span>
<span class="line"><span style="color: #D4D4D4">displayNextMotorInfoPanel()</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    // Only attempt to display a dashboard if motors exist</span></span>
<span class="line"><span style="color: #D4D4D4">    if (NUM_MOTORS &gt; 0)</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #D4D4D4">        // Determine the next motor in the motor list</span></span>
<span class="line"><span style="color: #D4D4D4">        int iNextMotorIndex =</span></span>
<span class="line"><span style="color: #D4D4D4">            (dynContains(DP_MOTOR_LIST, _dpCurrentMotorInfo) % NUM_MOTORS) + 1;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        _dpCurrentMotorInfo = DP_MOTOR_LIST&#91;iNextMotorIndex&#93;;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        // Open the Motor Info panel for the selected motor</span></span>
<span class="line"><span style="color: #D4D4D4">        RootPanelOnModule(</span></span>
<span class="line"><span style="color: #D4D4D4">            MOTOR_INFO_PANEL,</span></span>
<span class="line"><span style="color: #D4D4D4">            &quot;MotorInfoPanel&quot; + _dpCurrentMotorInfo,</span></span>
<span class="line"><span style="color: #D4D4D4">            motorInfoDashboard.ModuleName,</span></span>
<span class="line"><span style="color: #D4D4D4">            &quot;$motorDpe:&quot; + dpSubStr(_dpCurrentMotorInfo, DPSUB_DP)</span></span>
<span class="line"><span style="color: #D4D4D4">        );</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">When running the main.pnl panel in QuickTest, we can iterate through the relevant motor DPs by clicking the “Next Motor” button.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Picture7_Edited.png" alt="myMotor"/></figure>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Picture8_Edited.png" alt="myMotor2"/></figure>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Picture9_Edited.png" alt="myMotor3"/></figure>



<p class="wp-block-paragraph">So far, we’ve worked&nbsp;with panels of static widths and heights; however, developers can adjust panel reference dimensions, and users can sometimes resize a given window.&nbsp;OA provides functionality to accommodate for the positioning of objects within a panel when the overall panel dimensions shift.</p>



<p class="wp-block-paragraph">In the next edition of “Getting Started with WinCC OA,” we’ll take a brief look at panel layouts and how we can use them to dictate the real estate of a panel.</p>



<p class="wp-block-paragraph"><strong>Topics to look forward to in this series:&nbsp;</strong></p>



<ul class="wp-block-list">
<li><a href="https://static.dmcinfo.com/latest-thinking/blog/id/10313/getting-started-with-wincc-oa-part-12--modules-and-embedded-modules">Part 12: Modules &amp; Embedded Modules</a></li>
</ul>



<p class="wp-block-paragraph"><strong><a href="https://static.dmcinfo.com/contact">Contact</a>&nbsp;DMC to get started on your next WinCC project and learn more about our&nbsp;<a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/hmi-and-scada-programming/siemens-simatic-wincc-programming">Siemens SIMATIC WinCC Programming</a>as well as our&nbsp;<a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/hmi-and-scada-programming/wincc-open-architecture-development">WinCC Open Architecture Development.</a></strong></p>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://static.dmcinfo.com/blog/18628/getting-started-with-wincc-oa-part-12-modules-and-embedded-modules/">Getting Started with WinCC OA: Part 12 &#8211; Modules and Embedded Modules</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Creating Dynamic Ignition Perspective Projects, Part 3: Embedded Views and Flex Containers</title>
		<link>https://static.dmcinfo.com/blog/19104/creating-dynamic-ignition-perspective-projects-part-3-embedded-views-and-flex-containers/</link>
		
		<dc:creator><![CDATA[Casimir Smith]]></dc:creator>
		<pubDate>Fri, 27 Aug 2021 11:11:11 +0000</pubDate>
				<category><![CDATA[HMI and SCADA]]></category>
		<category><![CDATA[Ignition]]></category>
		<category><![CDATA[Manufacturing Automation & Intelligence]]></category>
		<category><![CDATA[MES]]></category>
		<category><![CDATA[container]]></category>
		<category><![CDATA[embedded]]></category>
		<category><![CDATA[flex]]></category>
		<category><![CDATA[ignition]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/19104/creating-dynamic-ignition-perspective-projects-part-3-embedded-views-and-flex-containers/</guid>

					<description><![CDATA[<p>One of the fastest growing SCADA/HMI platforms today is Inductive Automation&apos;s Ignition. In addition to the well-known Vision visualization module, Ignition&#160;contains Perspective, a web-friendly visualization module built from the ground up to work in any web browser &#8212;&#160;even on mobile! Although most Ignition functions work the same across Perspective or Vision, there are some adjustments&#160;to&#160;work&#160;better&#160;in [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/19104/creating-dynamic-ignition-perspective-projects-part-3-embedded-views-and-flex-containers/">Creating Dynamic Ignition Perspective Projects, Part 3: Embedded Views and Flex Containers</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">One of the fastest growing SCADA/HMI platforms today is Inductive Automation&apos;s <a href="https://inductiveautomation.com/ignition/" target="_blank">Ignition</a>. In addition to the well-known <a href="https://inductiveautomation.com/ignition/modules/vision" target="_blank">Vision</a> visualization module, Ignition&nbsp;contains <a href="https://inductiveautomation.com/ignition/modules/perspective">Perspective</a>, a web-friendly visualization module built from the ground up to work in any web browser &mdash;&nbsp;even on mobile!</p>

<p class="wp-block-paragraph">Although most Ignition functions work the same across Perspective or Vision, there are some adjustments&nbsp;to&nbsp;work&nbsp;better&nbsp;in a web-friendly environment. This multi-part blog will serve as a guide to setting up dynamic Perspective screens that take full advantage of the powerful new features.</p>

<p class="wp-block-paragraph">In the last two blogs, we created a status display to toggle an enable bit and display a numeric value. In this blog, we will combine&nbsp;those objects into an embedded view and use a flex repeater to create a dynamic layout.</p>

<h2 class="wp-block-heading">Creating a New Flex View</h2>

<p class="wp-block-paragraph">To create a new view, right click &quot;Views&quot; in the Project Browser then click &quot;New View&quot; In the popup. Be sure to change the root container type to &quot;Flex Container&quot;. The root container type cannot be changed once the view is created.</p>

<figure class="wp-block-image"><img decoding="async" alt="Create a new view with a flex root container" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/1_new_flex_view.png"  /></figure>

<p class="wp-block-paragraph">Next, select the view in the project browser and resize it using the width and height properties in the property editor. Change the dimensions to 400x100px.</p>

<figure class="wp-block-image"><img decoding="async" alt="Resize the view for it to be a template" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/2_resized_view.png"  /></figure>

<p class="wp-block-paragraph">Next, return to the main view and copy the toggle button, enable display, and numeric value display. Paste these three components into the new view&apos;s root container.</p>

<p class="wp-block-paragraph"><figure class="wp-block-image"><img decoding="async" alt="Copy your components from the main view" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/3_copy_from_main_view.png"  /></figure><figure class="wp-block-image"><img decoding="async" alt="Paste your components to the template view" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/4_paste_to_main_view.png"  /></figure></p>

<p class="wp-block-paragraph">The three views line up on top of each other in the flex container, which is not what we want. We need to configure the flex container and object position properties to best display our data.</p>

<h2 class="wp-block-heading">Configuring the Flex Container</h2>

<p class="wp-block-paragraph">The flex container has many different properties that determine how objects are displayed, the first is the direction. Switch this to &quot;row&quot; to change the orientation of the three objects.</p>

<figure class="wp-block-image"><img decoding="async" alt="Change the flex container direction" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/6_flex_container_props.png"  /></figure>

<p class="wp-block-paragraph">Now our objects are in a row, but they are not the correct size. We want the button, enable, and numeric display to take up different amounts of space. Luckily, there are position properties on each object that can achieve this exact behavior.</p>

<figure class="wp-block-image"><img decoding="async" alt="Row oriented flex container" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/7_row_flex_container.png"  /></figure>

<p class="wp-block-paragraph">Select the button object and find the position properties in the property editor. The basis determines how much space the object &quot;wants&quot; to take up. It can be in percent (%) or pixels (px). Set the button basis to 20%, the enable label basis to 30%, and the numeric label to 50%.</p>

<figure class="wp-block-image"><img decoding="async" alt="Change the basis in the object's position props" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/8_flex_position_props.png"  /></figure>

<p class="wp-block-paragraph">The other parameters are shrink, which decides if the object should shrink if there isn&apos;t enough space, and grow, which decides if the object should grow to take up unallocated space. We do not need to adjust these.</p>

<p class="wp-block-paragraph">After adjusting the basis, each object takes up the allotted percentage of space.&nbsp;There is one final tweak: adding a margin to the button so it is spaced away&nbsp;from the edges and other components.&nbsp;</p>

<figure class="wp-block-image"><img decoding="async" alt="With proper basis settings, the elements look better" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/9_spaced_flex.png"  /></figure>

<p class="wp-block-paragraph">Select the button and find the &quot;style&quot; property in the property editor. Press the plus button to add a new style entry. Name it &quot;margin&quot; and set the value to 5px. Alternatively, you can click the style card icon button to graphically view and edit style definitions.&nbsp;</p>

<figure class="wp-block-image"><img decoding="async" alt="Add a margin to the button to space it from other components" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/11_add_margin.png"  /></figure>

<p class="wp-block-paragraph">With a margin on the button, our flex container view looks ready to go! All that&apos;s left to do is to&nbsp;add it to our main view.</p>

<figure class="wp-block-image"><img decoding="async" alt="That is a nice looking flex container!" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/12_final_result.png"  /></figure>

<h2 class="wp-block-heading">Embedding in Another View</h2>

<p class="wp-block-paragraph">Embedding views within other views is easy. Just find your desired view in the project browser, then drag it into your current&nbsp;view. Alternatively, you can grab an &quot;Embedded View&quot; object from the toolbox, then set the path parameter to your view&apos;s path. The embedded view now acts as a singular object.</p>

<figure class="wp-block-image"><img decoding="async" alt="Drag your embedded view into the main view" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/13_drag_into_main_view.png"  /></figure>

<p class="wp-block-paragraph">In this blog, we learned how to create an embedded view template and add it to another view. <a href="https://static.dmcinfo.com/latest-thinking/blog/id/10253/creating-dynamic-ignition-perspective-projects-part-4-parameters-indirect-bindings-and-flex-repeaters">In the next blog</a>, we will add parameters to this template so we can create multiple instances to get data from different sources!</p>

<p class="wp-block-paragraph"><strong>Learn more about DMC&apos;s&nbsp;<a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/hmi-and-scada-programming/ignition-designer-programming">Ignition expertise</a>.&nbsp;&nbsp;<a href="https://static.dmcinfo.com/contact">Contact us</a>&nbsp;to get started on your next HMI, SCADA, or MES project.<br />
<br />
See other blogs in this series:&nbsp;</strong>Creating Dynamic Ignition Perspective Projects<br />
<a href="https://static.dmcinfo.com/latest-thinking/blog/id/10250/creating-dynamic-ignition-perspective-projects-part-one-bindings-and-transforms">Part 1: Bindings and Transforms</a><br />
<a href="https://static.dmcinfo.com/latest-thinking/blog/id/10251/creating-dynamic-ignition-perspective-projects-part-2-button-event-actions">Part 2: Button Event Actions</a><br />
Part 3: Embedded Views and Flex Containers<br />
Part 4: View Parameters,&nbsp;Indirect Bindings, and Flex Repeaters<br />
Part 5: Flex Repeaters with Variable Number of Instances (coming soon)<br />
Part 6: Changing Colors and Other Properties (coming soon)</p>
<p>The post <a href="https://static.dmcinfo.com/blog/19104/creating-dynamic-ignition-perspective-projects-part-3-embedded-views-and-flex-containers/">Creating Dynamic Ignition Perspective Projects, Part 3: Embedded Views and Flex Containers</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
