![]() |
Multimedia »
GDI »
Regions
Advanced
Creating alternate GUI using Vector ArtBy Keith RuleCreate visually complex, yet programmatically simple, non-rectangular GUIs |
VC6, MFC, GDI, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||

As Windows Programmers we know the following to be true:
Luckily, this "facts" aren't true. I personally believe that we are starting to see a transition from hard-coded, MS-looking GUIs to more unique and sometimes photo-realistic GUIs for applications. Currently you can see this trend in applications that are "skinned" and commercial applications like the photo-realistic Gizmos. When Apples Os X is release in about a year, I believe we will see an explosion of alternate GUIs for both the Apple and Microsoft platforms.
I feel that part of my job, as a software engineer, is to prepare for this future. To prepare I have been looking at several technologies:
I'm employed at a company where I have the good fortune to work closely with Industrial Artists and Human Factors Engineers. For the last several years, part of my job has been converting the Industrial Artist's art and Human Factors Engineer's behavior into elements for Windows applications. This has reinforced my opinion that most programmers are lousy artists and even worse interface-designers (just so you know I include myself in this broad, overly simplified generalization).
At my company the preferred tool for use by an Industrial Artist is Adobe Illustrator. This tool allows the creation of art as bitmaps, vectors, or a combination of both. It is my observation is that artists prefer working in vector art. This is for practical reasons. Vectors can be defined as individual objects that can be ordered, translated, rotated, and scaled independently.
I've also observed that Windows programmers have a mental block. All graphic problems are solved with bitmaps. Personally I hate bitmaps. They don't easily scale or rotate. They tend to be large. And you have to associate touch regions with the bitmap if you want to define any interesting behavior to them. In other word, bitmaps are difficult to work with and the result is often poor.
Since the artists I associate with prefer working with vector art anyway, I've been asking for the vector form of their art for my projects. I then run the files through a tool that I've written that extracts the vectors and text and converts them into C++ code. This article shows how to use this type of data to create interesting applications.
Disclaimer - Do not assume that the project shown here is either an example of good art or of good Human Factors design. It's just an example of what you can do with vectors.
Vector art is drawn the same way a painter paints. Elements of the image are painted from back to front with the later elements possibly obscuring some of the earlier elements. This means that you should never change the order that items are drawn. It also means that you should hit-test in the reverse order that items are drawn.
The following is an example of the output of a red circle. I created the drawing with CorelDraw. Saved the output as a Windows Meta File. I then run that file though a tool that I wrote that extracts, polygons, polylines, and text. The following code is output from this tool.
#include "StdAfx.h" #include "ArtCode.h" // Contains code that does hit-test, drawing, and region creation. static RECT bounds = {20, 20, 15980, 15740}; static POINT Polygon0Points[] = { {8000, 15740}, {8409, 15730}, {8814, 15700}, {9212, 15650}, {9605, 15580}, {9990, 15492}, {10368, 15386}, {10739, 15262}, {11101, 15121}, {11454, 14963}, {11798, 14789}, {12133, 14600}, {12456, 14395}, {12769, 14176}, {13071, 13942}, {13361, 13694}, {13638, 13434}, {13903, 13161}, {14154, 12875}, {14391, 12578}, {14614, 12270}, {14822, 11951}, {15015, 11622}, {15191, 11283}, {15351, 10935}, {15495, 10578}, {15620, 10213}, {15728, 9841}, {15818, 9461}, {15888, 9074}, {15939, 8682}, {15970, 8284}, {15980, 7880}, {15970, 7477}, {15939, 7078}, {15888, 6686}, {15818, 6299}, {15728, 5920}, {15620, 5547}, {15495, 5182}, {15351, 4825}, {15191, 4478}, {15015, 4139}, {14822, 3810}, {14614, 3490}, {14391, 3182}, {14154, 2885}, {13903, 2600}, {13638, 2326}, {13361, 2066}, {13071, 1819}, {12769, 1585}, {12456, 1365}, {12133, 1160}, {11798, 971}, {11454, 797}, {11101, 639}, {10739, 498}, {10368, 374}, {9990, 268}, {9605, 180}, {9212, 111}, {8814, 60}, {8409, 30}, {8000, 20}, {7590, 30}, {7186, 60}, {6787, 111}, {6395, 180}, {6009, 268}, {5631, 374}, {5261, 498}, {4899, 639}, {4545, 797}, {4201, 971}, {3867, 1160}, {3543, 1365}, {3230, 1585}, {2929, 1819}, {2639, 2066}, {2361, 2326}, {2097, 2600}, {1846, 2885}, {1608, 3182}, {1386, 3490}, {1178, 3810}, {985, 4139}, {808, 4478}, {648, 4825}, {505, 5182}, {379, 5547}, {272, 5920}, {182, 6299}, {112, 6686}, { 61, 7078}, { 30, 7477}, { 20, 7880}, { 30, 8284}, { 61, 8682}, {112, 9074}, {182, 9461}, {272, 9841}, {379, 10213}, {505, 10578}, {648, 10935}, {808, 11283}, {985, 11622}, {1178, 11951}, {1386, 12270}, {1608, 12578}, {1846, 12875}, {2097, 13161}, {2361, 13434}, {2639, 13694}, {2929, 13942}, {3230, 14176}, {3543, 14395}, {3867, 14600}, {4201, 14789}, {4545, 14963}, {4899, 15121}, {5261, 15262}, {5631, 15386}, {6009, 15492}, {6395, 15580}, {6787, 15650}, {7186, 15700}, {7590, 15730}, {8000, 15740}, }; static PolygonEntry Polygon0 = { "Polygon0", {20, 20, 15980, 15740}, RGB(218, 37, 29), 1, // PolyFillMode 129, Polygon0Points, }; // Draw Vector image - will scale to clientRect so if you want // to maintain the images aspect ratio please make sure the clientRect // passed also maintains that aspect ratio of the object. void DrawObject(CDC* pDC, const CRect& clientRect) { Draw(pDC, Polygon0, clientRect, bounds); } // Creates a region. Regions can be used for several things. // However the result of this call is usually used to create a // Window Region. void CreateRegion(CRgn& rgn, const CRect& clientRect) { CreateRegion(rgn, Polygon0, clientRect, bounds); } // TRUE on an element in the vector drawing is hit. BOOL HitTestObject(const CPoint& point, const CRect& clientRect) { if (HitTest(Polygon1, clientRect, bounds, point)) return TRUE; return FALSE; } // Returns the aspect ratio of the image. To use this you do the following: // newWidth = AspectRatio()*window.Height(); double AspectRatio() { CRect objectRect(bounds); return ((double) objectRect.Width())/((double) objectRect.Height()); }
To modify your dialog app all you need to do is set the window region to the regions of the combined vectors and then handle OnPaint messages. The logical place to set the window region is in OnInitDialog.
This code does the following:
BOOL CFlowerPowerDlg::OnInitDialog()
{
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
m_downItem = None;
// Maintain aspect ratio of drawing
CRect rect;
GetWindowRect(&rect);
rect.right = ((int) (rect.Height()*AspectRatio()))+rect.left;
CRgn wndRgn;
// Size Window to new aspect ratio
MoveWindow(&rect, FALSE);
// Get Screen Rect and convert to client coords
GetWindowRect(&rect);
ScreenToClient(&rect);
// Create a region for our window in client coords
CreateRegion(wndRgn, rect);
// Set Window region in client coords - the MS docs say this call is in
// Screen Coords, but only client coords work.
SetWindowRgn(wndRgn, TRUE);
CDialog::OnInitDialog();
return TRUE; // return TRUE unless you set the focus to a control
}
OnPaint is the stock output from the AppWizard expect for the non-iconic drawing. When drawing non-icon version of the dialog you do the following:
void CFlowerPowerDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { if (!m_bDialogUp) { CWindowDC dc(this); CMemDC pDC(&dc); CRect rect; GetWindowRect(&rect); ScreenToClient(&rect); DrawObject(&pDC, rect); CDialog::OnPaint(); } } }

To create your own C++ code out of vector art I've included the application I've written called ArtCode.exe. Just so you know, this application is complete hack. It was designed for one purpose, to turn vector art to code with the least work possible with the tools that I already had. I had Adobe Illustrator and CorelDraw. Because of that, the process of getting your vector art to C++ requires a reasonably current copy of CoreDraw (I've successfully used versions 6-9 for this). Here's the process (and yes it is quirky -- but it works):
Rotation, translation, and Scaling of vector art is easy, but if you don't recall how to do this from your linear algebra class (mine was 20+ years ago) you will need either a good computer graphics book or a good linear algebra book. All you do is set up a transformation matrix and do a matrix multiply to perform one or more of these operations. Once you see it you'll discover how simple this really is. A decent calculator helps too (I love my TI-92).
The ArtCode.exe program is completely unsupported. Please do not send me email asking for changes or to help you troubleshoot some problem you are having with it. It is very, very unlikely that I will respond to any such email. If you do get stuck and absolutely need help you might try one of the discussion forums on www.codeproject.com.
The tool will not work if you try to open your run-of-the-mill Windows Metafiles. The tool supports a very, very small subset of Windows Metafile commands so you are guaranteed to get no graphics or a subset of your graphics if you import a typical WMF. The step of exporting to Adobe Illustrator format first is absolutely required in most cases.
The point of this article isn't to cause any serious changes in how you design GUIs. The goal is to stimulate some thought about where GUI development is going, and to help you prepare for the future that you see coming. It also should show you how much easier working with vector graphics can be than working with bitmaps graphics.
You may use the code you find included in this project anyway you like. However, the art was derived from my legal copy of CorelDraw. I believe that it is legal for me to use the derived version of the art in my code, however please don't use this art in your project unless you own CorelDraw.
| You must Sign In to use this message board. | |||||
|
|||||
|
|||||
|
|||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 6 Feb 2000 Editor: Chris Maunder |
Copyright 2000 by Keith Rule Everything else Copyright © CodeProject, 1999-2009 Web20 | Advertise on the Code Project |