
Introduction
It is very natural that in the Internet era, more and more applications are getting "Web Style" HTML alike user interfaces. HTML pictorial graphic UI attracts users and gives them an impression of lightness and easiness of tasks they need to accomplish using the software.
Let us think about HTML as not only a way to describe screen layout with active (hyperlinks) areas and embedded resources but rather a modern application design and management methodology.
Using the proposed Lightweight Embeddable HTML Layout Engine, the following tasks could be achieved in a very convenient way:
- Create applications with a "Web style" user interface.
- Separate presentation layer from user interaction logic in complex applications.
- Create "skinable" user interfaces.
- Design applications with the support of several UI languages. As a rule, each language (or locale) has its own requirement for screen layout, since the same phrase (e.g. input field caption) could have different length in different languages. Using different HTML resources for different languages could help you keep the international issues manageable.
- Create resizable screen layouts and manage complex input forms. HTML engine may play a role of an ultimate layout manager as it does all functionality which could be found in java.awt.*Layout classes.
- Design database driven applications where all needed resources to visualize objects are stored as HTML in the same database.
- Create embedded help systems, etc.
This article describes how to use HtmLayout engine in your WTL projects.
HtmLayout
Terra Informatica HtmLayout Engine is a native Windows� window class which resides in HtmLayout.DLL (about 400K). Native here means that it uses pure Windows API calls and no other integration technologies like COM/ActiveX or .NET.
HtmLayout engine interacts with the hosting application through WM_NOTIFY messages.
HtmLayout Embedding
You may think about HtmLayout window as an intelligent container which does two main tasks:
- Rendering of loaded HTML
- Laying out of child controls (defined by HTML's
<INPUT> tags).
HtmLayout treats <INPUT>, <TEXTAREA> and other "input" elements as definitions of "placeholders" for application supplied child controls and views. When parsing these tags, HtmLayout generates WM_NOTIFY/HLN_CREATE_CONTROL "events". Application itself can create child windows interpreting collection of tag's attribute values and optional <PARAM>s provided by HtmLayout. Thus, it is possible to define any custom control of your choice in HTML:
<P>Name to search:<INPUT id=32103
name=TextToSearch type=text width=100% minwidth=40>
or select item from here:</P>
<WIDGET id=32104 name=ItemToPick type=treeview haslines linesatroot
hasbuttons width=100% height=100% minheight=40>
<PARAM name=fruits value=0>
<PARAM name=fruits/apples value=1>
<PARAM name=fruits/oranges value=2>
<PARAM name=fruits/cherries value=3>
<PARAM name=vegetables value=0>
...
</WIDGET>
(Tag WIDGET is HtmLayout's counterpart of APPLET tag in HTML).
HtmLayout events (notification messages)
While loading HTML text, HtmLayout will raise two types of events - (send notification messages in WM_NOTIFY form):
HLN_CREATE_CONTROL - a request to the host to create a control
HLN_LOAD_DATA - a request to the host to load images referred by the HTML text. The application can load picture from resources or other storage such as a database. HtmLayout can also load data from local file system or from the Internet.
If the source HTML contains hyperlinks, HtmLayout will send HLN_HYPERLINK notifications when mouse cursor enters, leaves, or the left button is clicked on the hyperlinked areas.
The code for handling the creation of controls in response to WM_NOTIFY/HLN_CREATE_CONTROL notification might look like this:
struct NMHL_CREATE_CONTROL
{
NMHDR hdr;
LPCWSTR type;
LPCWSTR name;
LPCWSTR id;
int tagType;
LPCSTR* attributeNames;
LPCWSTR* attributeValues;
int attributeCount;
LPCWSTR* optionNames;
LPCWSTR* optionValues;
int optionCount;
HWND outControlHwnd;
}
inline LRESULT
CHtmLayoutWindowEx::OnCreateControl
(LPNMHL_CREATE_CONTROL pnmCreateCtl)
{
int style = WS_CHILD | WS_TABSTOP | WS_VISIBLE;
if(pnmCreateCtl->type == 0 || pnmCreateCtl->type[0] == 0)
return 0;
LPCTSTR clsname = 0;
if(wcsicmp(pnmCreateCtl->type,L"treeview") == 0)
{
clsname = WC_TREEVIEW;
style | = WS_VSCROLL;
if(IsAttributeExists(pnmCreateCtl,"haslines"))
style | = TVS_HASLINES;
if(IsAttributeExists(pnmCreateCtl,"linesatroot"))
style |= TVS_LINESATROOT;
if(IsAttributeExists(pnmCreateCtl,"hasbuttons"))
style |= TVS_HASBUTTONS;
if(IsAttributeExists(pnmCreateCtl,"editlabels"))
style |= TVS_EDITLABELS;
}
HWND hWndCtl=
CreateWindowEx(WS_EX_CLIENTEDGE,
clsname,0,style,0,0,0,0,m_hWnd,0,0,0);
pnmCreateCtl->outControlHwnd = hWndCtl;
return 0;
}
HtmLayout methods (messages)
Host applications can use either WP_HL_ACTION_LOAD_HTML (from text buffer) or WP_HL_ACTION_OPEN_FILE (from file) "methods" to load HTML text into HtmLayout window.
The WP_HL_ACTION_GET_MIN_DOCUMENT_WIDTH and WP_HL_ACTION_GET_MIN_DOCUMENT_HEIGHT (for given width) methods allow the application to get information about dimensions of the loaded document.
All these "methods" are activated by a simple call of:
::SendMessage(hWnd, WM_HL_ACTION, WPARAM(WP_HL_ACTION_action_code), LPARAM(action_params))
or by a call of: SetText, OpenFile, GetDocumentMinWidth and GetDocumentMinHeight functions of the WTL wrapper class provided by HtmLayout SDK.
More details of HtmLayout embedding principles could be found here: HtmLayout API and embedding principles.
The sources of WTL wrapper and demo application are in samples/WTL of HtmLayout SDK distribution.
HtmLayout markup flavor
HtmLayout markup language is pretty much HTML 3.2. It was extended to make it more suitable for screen layouts limited not only by the width, but also by the height of the view. Also, there are some enhancements to support "expandable" and gradient-filled backgrounds.
HtmLayout supports GIFs, JPEGs and PNG with alpha channel (transparency).
More details about HtmLayout markup could be found here: HtmLayout markup language.
Platforms supported
HtmLayout.DLL is available for all existing Windows platforms including Windows Mobile and is free to use in free applications (those which distributed freely and are not bringing income in any form).
In addition to WTL wrapper, HtmLayout SDK includes sources of wrappers for MFC, .NET (C#) and ActiveX (VB).
For details and latest updates visit, HtmLayout home.
|
|
 |
 | I want to apologize ... Igor Vigdorchik | 10:04 26 Nov '09 |
|
 |
Andrew,
I want to apologize for the comment I've made 6 years ago that this article sounds like an advertisement. I was wrong. Thanks a lot for giving your component away and allowing other developers to use it without many strings attached. And explaining how to do use it.
Regards, Igor.
|
|
|
|
 |
 | Help,please about x64 memory leaks. Tangyoufox | 21:40 13 Apr '09 |
|
 |
Hi C_SMILE: Could you receive my sample.exe ? Our customers need our product in x64 .But it has terrible memory leaks. I have told you this situation about 20 days before.But you have no answer.Have you been on holiday or haven't receive my sample? If you have not received my samlple.I will send it to you again.Please help me to solve this problem. It is very urgent.Thank you..
|
|
|
|
 |
|
 |
Just download version 3.3.1.17. It contains fix in x64 version. It was not a memory leak strictly speaking - dynamic updates were causing memory build-ups that are freed but only after document reload.
|
|
|
|
 |
 | Failed to send my sample,help! Tangyoufox | 23:15 24 Mar '09 |
|
 |
Hi C_SMILE: I am sorry to tell you that htmlayout@terrainformatica.com domain terrainformatica.com MX query return retry.So i cann't send my sample to you . Could you please send me a e-mail with any content to me(3792615@163.com).And then I reply it with my sample .Do you have any other e-mail ,such as yahoo,hotmail ...
|
|
|
|
 |
 | help,about memory leak in x64 Tangyoufox | 22:49 8 Mar '09 |
|
 |
Hi,c_smile: I has completed my project on the whole,but there still has a problem. I want to generate my .exe in x64 but it has terrible memory leak ,about 100k~150k per second. I know that the memory leak generate in my timer,but it has no memory leak in x32. I have already replaced my "htmlayout.lib" and "htmlayout.dll" from x32 to x64 ,so you could exclude the possibility.
I have check the problem for days, finall i found that when i call the htmlayout function,the memory leak appears. the code is like this:
htmlayout::dom::element tab_to_switch = m_root.find_first("#user_error"); //ok tab_to_switch.post_event(ACTIVATE_CHILD); //ok m_index_time_show.GetElement().set_style_attribute("visibility",_T("hidden")); //leak m_login_error_reason_one.GetElement().set_text(_T("some infomation")); //leak
I use the new SDK ,date is 2009.03.06. Have you test the memory leak in x64 about htmlayout.dll? If you have done this,may be it is my problem when i call your function. In that way ,please give me a example in x64 with MFC that has no memory leak. Thank you.
|
|
|
|
 |
|
 |
I am not able to read your mind or hard drive from Canada. So have no clue where in your GetElement() method happens that leak.
What exactly is that m_index_time_show and how GetElement() looks like?
|
|
|
|
 |
|
 |
I define a class for CStatic Control ,and m_index_time_show is an object for CStatic Control. The following is "GetElement() " define: class CHtmlLayoutElement// : public htmlayout::dom::element { public : CHtmlLayoutElement(){}; ~CHtmlLayoutElement(){};
// CHtmlLayoutElement(HELEMENT h) { use(h); }
virtual BOOL IsValid(HELEMENT ctrl, CString& strType); virtual BOOL AttachControlSite(HELEMENT ctrl);//{return TRUE;}; virtual BOOL AttachControlSite(htmlayout::dom::element root, LPCTSTR lpszCtrlName);
htmlayout::dom::element GetElement() { return m_element; }
protected: htmlayout::dom::element m_element; };
|
|
|
|
 |
|
 |
If you have this method exactly as:
htmlayout::dom::element GetElement() { return m_element; }
then it will not leak any memory.
|
|
|
|
 |
|
 |
But it really happens.In x32 ,it is ok,but in x64 it leaks very terrible. So i have no idea to deal with it .I am doing a test now .Using your sample "win64" to call the same code to see whether there is memory leak.
|
|
|
|
 |
|
 |
Hi c_smile:
I have test it in x64,it leaks terrible.But in x32 ,it is ok. I have packeted my sample .Could you please give me a e_mail .And I will send it to you.Thank you.
|
|
|
|
 |
|
 |
You can send it to htmlayout@[domain-in-my-profile]
|
|
|
|
 |
|
 |
I donn't know the meanning of [domain-in-my-profile].I post my email to htmlayout@codeproject.com,but it cann't post success. So i have posted it to the email address info@terrainformatica.com.Please check it .Thank you.
|
|
|
|
 |
|
 |
Do you see my photo above? My domain is on 6th line on the right of it.
|
|
|
|
 |
|
 |
I have posted again.please check it .
|
|
|
|
 |
|
 |
Hi C_SMILE: I am sorry to tell you that htmlayout@terrainformatica.com domain terrainformatica.com MX query return retry.So i cann't send my sample to you . Could you please send me a e-mail with any content to me(3792615@163.com).And then I reply it with my sample .Do you have any other e-mail ,such as yahoo,hotmail ...
|
|
|
|
 |
 | About the control of textarea Tangyoufox | 19:59 22 Feb '09 |
|
 |
Hi ,c_smile: I have a question about the control of textarea. In my file of html ,it has a "textarea " like following: <textarea class="apply-second" cols="50" type="textarea" id="Textarea"></textarea> It works well ,but when i click the right button of my mouse,the UI appears an popup menu to do some edit work ,just like "UNDO","COPY". how can i to forbid the popup menu? I do like this : else if( type == UI_STATE_CHANGED || type == POPUP_REQUEST || type == POPUP_READY) { if( str_id == "the id of textarea") return TRUE; } But it has no function.Please tell the way to solute the problem.Thank you.
|
|
|
|
 |
|
 |
If you want to discard menu completely then define something like this in your CSS:
textarea#someid { context-menu:none; }
If you just want to provide your own menu then define
textarea#someid { context-menu:url(res:my-textarea-menu.htm); }
or
textarea#someid { context-menu:selector(menu#my-textarea-menu); }
In both cases the menu should look like this:
<menu .plaintext-context #my-textarea-menu>
<li command="richtext:undo"
style="foreground-image:url(res:edit-undo.png)"
>Undo<span class="accesskey">Ctrl+Z</span></li>
<hr/>
<li command="richtext:cut" style="foreground-image:url(res:edit-cut.png)"
>Cut<span class="accesskey">Ctrl+X</span></li>
<li command="richtext:copy"
style="foreground-image:url(res:edit-copy.png)"
>Copy<span class="accesskey">Ctrl+C</span></li>
<li command="richtext:paste"
style="foreground-image:url(res:edit-paste.png)"
>Paste<span class="accesskey">Ctrl+V</span></li>
<hr/>
<li command="richtext:selectall"
>Select All<span class="accesskey">Ctrl+A</span></li>
</menu>
You can define your own images and/or text.
|
|
|
|
 |
|
 |
Hi,C_SMILE: If i discard menu completely ,the edit control doesn't support the edit work. how can i translate your right popu menu from English to Chinese? I tryed to build my own menu ,but it cann't be shown. Could you please send me a sample? My e_mail is 3792615@163.com. Thank you.
|
|
|
|
 |
|
 |
Here is the sample:
<html>
<head>
<style>
plaintext { font: 10pt monospace; height:*; context-menu: selector(menu.context.for-plaintext); } </style>
<menu.context.for-plaintext>
<li command="richtext:undo" style="foreground-image:url(res:edit-undo.png)"
>Undo It!<span class="accesskey">Ctrl+Z</span></li>
<hr/>
<li command="richtext:cut" style="foreground-image:url(res:edit-cut.png)"
>Cut<span class="accesskey">Ctrl+X</span></li>
<li command="richtext:copy"
style="foreground-image:url(res:edit-copy.png)"
>Copy<span class="accesskey">Ctrl+C</span></li>
<li command="richtext:paste"
style="foreground-image:url(res:edit-paste.png)"
>Paste<span class="accesskey">Ctrl+V</span></li>
<hr/>
<li command="richtext:selectall"
>Select All<span class="accesskey">Ctrl+A</span></li>
</menu>
</head>
<body>
<h1>Demo of behavior:plaintext.</h1>
<plaintext>
Hello world </plaintext>
</body>
</html>
Load it and you should see context with changed first item ("Undo It").
If you use Chinese then do not forget about encoding. I suggest to use utf-8.
|
|
|
|
 |
 | I am sorry to trouble you again,C_Smile.About the event of button. Tangyoufox | 19:37 16 Feb '09 |
|
 |
hi,C_Smile: My project is about to finish,thank you for your kind help.But there still has a problem about the event of button. When I move my mouse and click on a button,the button i clicked has no button_behavior. But some other buttons have the button_behavior.I don't know why,could you please tell me the resason? Is there a event like WM_BUTTONUP in windows ? I have checked the events ,there is only two events about button "BUTTON_CLICK" and "BUTTON_PRESS".
|
|
|
|
 |
|
 |
Behaviors are getting applied to DOM elements through CSS.
List of built-in behaviors is here: http://www.terrainformatica.com/wiki/h-smile/built-in-behaviors/start[^]
Behavior button can be applied to any DOM element, thus any DOM element may behave as a button and so to generate BUTTON_CLICK event. Just verify that you have something like this:
#myelement { behavior:button; ... }
in your styles. BTW: people from http://htmlayoutlab.com/[^] created nice tool named HTMLayoutSpy that allows you to inspect DOM and so to find what styles and attributes are applied.
|
|
|
|
 |
 | Help,about too much tabs. Tangyoufox | 16:26 10 Feb '09 |
|
 |
Hi,C_Smile: I have a problem in my project about tabs.My .exe is based on dialog,it has many tabs.But the length of my interface is limited .If the tabs overflows the max_length,it turns into sightless. I consult other .exe, if they have too much tabs,a pair of buttons will be shown to go next or to go previous.How can i realize that? Thank you.
|
|
|
|
 |
|
 |
There are many ways of how to do this. In ScIDE (from Sciter SDK)[^] when tabs overflow they move to popup menu (on the right).
Its implementation is in file sciter/sdk/scapps/sciter.ide/tabstrip/tabstrip.tis That is in TIScript but you can write the same for HTMLayout in C++ as a behavior.
Main method there is onSize() event handler. It moves items off and on "offstrip" popup menu when it is needed:
function onSize() { var offstripButton = this.select("widget.off-strip"); var offstripList = this.select("widget.off-strip menu"); var tabs = this.select("widget.tabs"); function moveFromOffstrip(tab) { for(var ot in offstripList) if( ot.tab === tab ) { ot.tab = null; ot.detach(); break; } tab.@#visible = true; if(!offstripList.length) offstripButton.enabled = false; } function moveToOffstrip(tab) { if(!offstripList.length) offstripButton.enabled = true; var li = tab.clone(); li.tab = tab; offstripList.insert(li,0); tab.@#visible = undefined; } var tabs_width = tabs.box(#width);
for(var tab in tabs ) { var right_edge = tab.box(#right,#border,#parent); if( (right_edge < tabs_width) && !tab.@["visible"] ) moveFromOffstrip(tab); else if( (right_edge > tabs_width) && tab.@["visible"] ) moveToOffstrip(tab); } }
The whole implementation of this scripting behavior is around 160 lines that could be ported to C++ behavior practically one-to-one.
|
|
|
|
 |
 | how can i get the selected node info from a tree ctrl xifan | 22:49 14 Jan '09 |
|
 |
In the html file: HtmLayoutSDK\html_samples\forms\tree-views.htm. What's more, is there any thing wrong with http://www.terrainformatica.com/htmlayout?, i can not get in for a long time.
thank you very much.
|
|
|
|
 |
|
 |
Use this:
dom::element select_ctl = ...; dom::element current_option = select_ctl.find_first("option:current");
And in general: htmlayout based UI is a collection of uniform DOM elements. Some of these DOM elements have behaviors applied to them. Such DOM element with the behavior is what that is known as Control in terms of Windows.
This means that in 90 percents of cases questions "how can i get ...?" can be translated into "what CSS selector I need to get ...?".
browse.exe has simple and pretty useful Element Probe (menu: Debug -> Element Probe On). That will show you DOM structure. And list of supported selectors is here: http://www.terrainformatica.com/htmlayout/selectors.whtm[^]
|
|
|
|
 |
|
|
Last Updated 11 Oct 2003 |
Advertise |
Privacy |
Terms of Use |
Copyright ©
CodeProject, 1999-2010