GacUI and design patterns (I) -- Preface

Source: Internet
Author: User

Speaking of GacUI (http://www.gaclib.net/,gac.codeplex.com), in fact this idea has been in my junior year. However, due to lack of experience, I was not able to make it until the National Day of last year (2011. It has been almost a year since now, and GacUI can also be used to write some C ++ GUI programs that are not particularly brutal. Some people asked a few days ago, why do I need to do this when the PC is almost finished and most of the guis are already using C? In fact, there are two reasons: the first one I like to toss C ++, and the second one C ++ does not seem to have a very good GUI, so I also want to try it, if it is done, it will be maintained. If it is not done well, it can also improve its own level. In short, it will not waste time. So I was thinking that GacUI has been written for almost a year now, and recently I have seen several people on cppblog who want to engage in GUI, so I want to take some design ideas of GacUI, and I have written these ideas. By the way, I will introduce the architecture of GacUI, so that some interested people (especially Assembly Heads) can also make great efforts.

The most important aspect of GacUI architecture is cross-platform. Of course, this does not necessarily mean that I will port GacUI to any other operating system in the future, but at least the two APIs of Windows Classic Desktop and Metro have nothing to do with them at the same time, it is also a cross-platform. And even based on the same API, there are different Renderer APIs, such as release GDI, such as release Direct2D, which are completely different. The Design of GacUI should at least eliminate their differences. Of course, there is a good technical way to ensure that GacUIIncludes. h does not contain Windows. h any content-So at least in the header file, everything is irrelevant to Windows. Of course, in the non-GUI part, we still need Windows. h, and some people like to do some hack operations on GacUI, so I am still in GacUI. h provides several additional Windows dependencies. h function to expose some internal details. So how to cross-Classic Desktop and Metro? There is a simple method, that is, you can give some macro Switches during compilation, such as GACUI_WINDOWS_CLASSIC_DESKTOP (default) or GACUI_WINDOWS_METRO to block unnecessary parts. Of course, this part will not be added before it is migrated to Metro.

Based on this idea, if you read the GacUI code, you will find it in the file \ Libraries \ GacUI \ Source \ NativeWindow \ GuiNativeWindow. h defines an INativeController interface, and currently only one implementation is available for Windows Classic Desktop. INativeController has a lot of content and provides operations related to specific platforms, such as reading and writing image files, creating and eliminating windows, and performing display operations, as well as various input and output operations. Implementing an INativeController from the ground up is still cumbersome, because GUI, which is heavily dependent on the operating system, wants to be separated and finds that it relies on a large amount of APIs. This explains why there are hundreds of Methods returned by the XXXService functions of INativeController. However, porting from Classic Desktop to Metro is relatively simple, because most of the content can still be shared.

The second is the Renderer. The Renderer and platform are cross-dependent. For example, OpenGL can be used on linux and Classic Desktop, Direct2D can be used on Classic Desktop and Metro, and GDI can only be used on Classic Desktop. Therefore, this is why I didn't write the Renderer in INativeController, but blocked the Renderer, and didn't provide its interface in GacUIIncludes. h. But considering that GacUI is a GUI library that supports skin replacement, you must let the skin decide how to draw the image on its own. Then I thought of a way to remove the entire Renderer structure and replace it with various elements (IGuiGraphicsElement ). The so-called elements are something like square, circle, fill, gradient, and text. The skin assembles the elements according to certain typographical relationships (described below, then a small system in GacUI will combine the Bridge and Abstract Factory modes (refer to \ Libraries \ GacUI \ Source \ GraphicsElement \ GuiGraphicsElement. h) To assign the Renderer object (IGuiGraphicsRenderer) to these elements ). Then, the graph element and the Renderer use the Listener mode to exchange information. The advantage is that when the element is changed, the special Renderer object of this element object can select cache information, and then during window rendering, you only need to access all the Renderer objects (a tree is formed by the combination of GuiGraphicsComposition in the typographical object) so that they can render themselves.

The element contains all the data to be rendered, but the size is not written in, because the size should not be the responsibility of the Renderer, but the layout object. The typographical object itself is a tree, and there are some relationships between the root nodes of the node, so that the STACK layout, table layout, alignment (to some sides) Layout and other specific typographical algorithms can be realized. A typographical object can be placed with a metadata object and filled with it. Therefore, it is obvious that some typographical objects are only used to calculate the intermediate size results, and not necessarily have graphic meta objects. At the beginning of rendering, the layout object first obtains data from the primitive object, and then recursively calculates the size of the entire layout tree, finally, the size is handed over to the dedicated Renderer object attached to the above primitive object for rendering.

You may wonder if the rendering performance would be low if tens of thousands of virtual functions need to be called at a time? Of course, compiling to Release will find that GacUI performance is still quite high. There are two reasons. First, I made some optimizations to typographical objects. For example, the size of an object must be at least greater than that of all sub-objects. This computation is fast and requires no cache. However, all the small grids in a table layout will be squeezed out from each other. The calculation of this item is rather complicated (the more complex it is, the less complex it is, and the coefficient is not smiling), so the result is to be cached. But when does it need to be re-computed? The measurement method is very simple, that is, when the minimum size of each grid changes. In fact, most skins use tables for formatting, which means that most results are cached. Therefore, you only need to make some small calculations for the size of the layout part during each rendering. Each typographical object in a complex layout is related to each other. A typographical object changes and may cause the size of another typographical object to be modified. Therefore, the simplest method is, if you do not save the size, you can calculate it once again. On this basis, the entire calculation process will become faster by caching the table layout. Therefore, although a considerable amount of computation is required for every drag or mouse over a window, an intelligent cache not only improves the computing speed, in addition, when adding a new typographical object type, you do not need to consider whether you will be cached or not, and the development is quite pleasant.

Therefore, the above three modules (operating system API isolation, Renderer, and typographical objects) are enough for me to open a window in the system and then put a variety of things on it, for example, you can combine them into a vector chart that looks very close to Windows 7. What should I do with the control? In fact, a control is to modify a large number of elements on a typographical object by receiving user input. The user's input interacts with the status of the control (GuiControl), and then the control submits the status change to the control's skin (GuiControl: IStyleController ), at last, the skin modifies the metadata to display the status change to the user. A typical example is that when you use Windows 7 skin, move the mouse over the button and it will trigger an animation to slowly turn blue.

The general architecture of GacUI is like this. In the following articles, I will introduce the internal structure of each sub-system in detail and take the following code as a guide.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.