thoughts on a GUI component library

Hi All, I have been working on revising my GUI library that is currently in the sandbox. The motivation for doing this was Andy Little's comment that most GUI libraries start from a particular operating system and then abstract its interface, providing work-arounds for other GUI systems. There are several considerations to make with a GUI library. For insatance, it should be possible to support GUI interfaces on portable devices (e.g. Palm Pilot/PalmOS) and terminal devices (like is done with the VIM editor). With these devices, code needs to be written to provide common components such as buttons. Also, the target operating system places design problems on creating a generic interface. For example, Windows supports char * and wchar_t * versions of its API, but the version that should be used depends on whether you are targetting Windows 9x or NT based systems. Windows also requires each component type to be registered before you can create an instance of it. Each operating system has different arguments that it passes when an event is generated, containing data relating to that event. Consideration must be made to allow events to be written generically, but also allow you to hook into OS-specific events and get OS-specific data. With all this in mind, how do you design a GUI library for C++? Although a GUI component exists on the screen and is drawn on that screen, the components and graphics elements should be kept seperate, since it is primarily the OSs role to render a component. There are shared elements (mostly the position, size and area types) and the graphics layer should allow for graphics-based events to be handled by the components library. Taking a look at how C++ is designed, it is predominantly data orientated. That is, C++ allows you to create new data types that fit into the language via operator overloading. The STL provides collections of data and algorithms for manipulating those collections. Terminal-based applications are supported by I/O streams that allow you to send data out and read data in. I have taken this as the primary design feature when implementing the GUI components. Thus, each component has an event to signal user interaction (ondatachanged, onselectionchanged, onpressed) and data that is associated with the component. The first thing that comes to mind when reading "data that is associated with the component" is data binding. I think it is a mistake to build data binding directly into the component architecture. The reason for this is twofold: You would need to use templates to bind the different data objects to the control which makes it harder to implement the controls in a platform-independant way and can lead to code bloat. Also, consider having a textbox widget that you use to enter the age. Having: gui::textbox< long > age; How does the textbox perform the conversion? By storing the data as a string, the user can extract the information on data collection like this: long age = boost::lexical_cast< long >( age_input.get_text()); or long age = ::atol( age_input.get_text()); Another thing to take into account is when an input field has a validity based on other component values. For example, the valitity of a dates day field is dependant on month and year. In this instance, it is best to put all the validation logic in the base component and extract the data to a date class such as Boost.DateTime's date. A component has a size and position, as well as visibility (visible or hidden) and enabled/disabled states. The component should make it easy to interoperate with native API. The majority of the current proposals (mine included) have taken the approach of providing native interoperability with the OS-specific data structures. This is very difficult to maintain properly and support generic code because of the different names of the data elements, types used (long or float) and whether an area is (position + size) or (top-left + bottom-right). Also, most OSs have (0,0) being the top-left corner, but MacOS has (0,0) being bottom-left. With this in mind, I have taken a drastic approach: do not provide native interoperability for size, position and area. I have designed them as: struct position{ float x; float y; }; struct size{ float dx; float dy; }; struct area { float top; float left; float width; float height; }; This means that the interface must convert these to the native representations and vise versa. The current implementation (Windows specific at this time) can be found at: http://uk.geocities.com/msclrhd/gui/gui.zip Thoughts? Comments? Regards, Reece

Reece Dunn wrote:
With this in mind, I have taken a drastic approach: do not provide native interoperability for size, position and area. I have designed them as: [...]
This means that the interface must convert these to the native representations and vise versa.
The VisualAge Classlibrary did that (which has been renamed to OCL and, alas, is now obsolete). Try to google some information on it to get ideas. It was a very good class library. I was quite satisfied with it. OS/2 - like Mac - has (0,0) on lower left. The OCL was crossplatform with OS/2, Windows and AIX. Regards Hajo

The first thing that comes to mind when reading "data that is associated with the component" is data binding. I think it is a mistake to build
What do you mean by this? Could you give an example?
The majority of the current proposals (mine included) have taken the approach of providing native interoperability with the OS-specific data structures. This is very difficult to maintain properly and support generic code because of the different names of the data elements, types used (long or float) and whether an area is (position + size) or (top-left + bottom-right). Also, most OSs have (0,0) being the top-left corner, but MacOS has (0,0) being bottom-left.
With this in mind, I have taken a drastic approach: do not provide native interoperability for size, position and area. I have designed them as:
struct position{ float x; float y; }; struct size{ float dx; float dy; }; struct area { float top; float left; float width; float height; };
This means that the interface must convert these to the native representations and vise versa.
I would say that this is the correct approach. As a side-node, I'm moderately against having float coordinates. Why would you think int is not enough? Best, John -- John Torjo, Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/ -- http://www.torjo.com/cb/ - Click, Build, Run!

John Torjo wrote:
The first thing that comes to mind when reading "data that is associated with the component" is data binding. I think it is a mistake to build
What do you mean by this? Could you give an example?
I gave examples in my explanation. Let's say you have a textbox component. To bind it to generic data, you would need something like: template< typename Data > class gui::textbox; This would allow: gui::textbox< std::string > name; gui::textbox< long > age; But: How do you convert the string data into a long? I suppose you could have a conversion parameter, so you would do: gui::textbox< long, lexical_converter< long > > age; However, because textbox is now a template, you get potential code bloat, especially if you are templating a more complex component such as a table (where in windows this is a "virtual" ListView control in report mode). I want to stear away from using templates as much as possible, using them where necessary, and keep the design as simple as it can be.
With this in mind, I have taken a drastic approach: do not provide native interoperability for size, position and area. I have designed them as:
struct position{ float x; float y; }; struct size{ float dx; float dy; }; struct area { float top; float left; float width; float height; };
This means that the interface must convert these to the native representations and vise versa.
I would say that this is the correct approach.
As a side-node, I'm moderately against having float coordinates. Why would you think int is not enough?
From the various discussions, it is down to precision in caclculation. Usually, this would be when rounding floating values to integer boundaries. For example:
x = 2.6 + 5.6 = 8.2 as an integer expression, is this: x = 2 + 5 = 7; // using floor(val) x = 3 + 6 = 9; // using ceil(val) or round(val) In this case, the integer expressions are out by 1 depending on what rounding scheme is used. I took actual values to show the case above. If these were values in an algorithm that performed anti-aliasing for example, the anti-aliasing would not calculate the correct values. Note that for integer-based coordinate systems, the values are converted to integers when needed, but otherwise are left as floating values to retain precision. Regards, Reece

gui::textbox< long, lexical_converter< long > > age;
However, because textbox is now a template, you get potential code bloat, especially if you are templating a more complex component such as a table (where in windows this is a "virtual" ListView control in report mode). I want to stear away from using templates as much as possible, using them where necessary, and keep the design as simple as it can be.
Yup, I certainly agree.
In this case, the integer expressions are out by 1 depending on what rounding scheme is used. I took actual values to show the case above. If these were values in an algorithm that performed anti-aliasing for example, the anti-aliasing would not calculate the correct values.
I would say it would be the algorithm's task, if it needs such precision, to convert from integer into floats, and then feed back the results in integers. Or maybe I'm just too optimistic :) Best, John -- John Torjo, Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/ -- http://www.torjo.com/cb/ - Click, Build, Run!

How about GUIs which simply support floating point coordinates natively? I read that Cocoa uses floats for coordinates, and I would wildly guess that Avalon will make use if float vectors, as well (at least if the fancy 3D integration is remotely useful ;-). Cheers, Michael

Appendix: IIRC many of those small, home-brewn/hobby/amateur GUI libraries for OpenGL or stuff also support floating point coordinates. Interestingly enough, the GUI framework that comes with the DirectX SDK does *not* (possibly because the coordinates are in screen space -- is this what you necessarily want, though?). On Wed, 15 Dec 2004 10:58:37 -0500, Michael Walter <michael.walter@gmail.com> wrote:
How about GUIs which simply support floating point coordinates natively? I read that Cocoa uses floats for coordinates, and I would wildly guess that Avalon will make use if float vectors, as well (at least if the fancy 3D integration is remotely useful ;-).
Cheers, Michael

Michael Walter wrote:
Appendix: IIRC many of those small, home-brewn/hobby/amateur GUI libraries for OpenGL or stuff also support floating point coordinates. Interestingly enough, the GUI framework that comes with the DirectX SDK does *not* (possibly because the coordinates are in screen space -- is this what you necessarily want, though?).
As far as I can see, the DirectX framework uses a Device Context handle (HDC) to draw contents to and a HDC uses integers to specify the coordinate values. However, it has vectors and matrices that use float values. The mention of coordinates in screen space makes me see another advantage of using floating point values: you can use them to store any coordinate scale value, e.g. (10.45f, 2.77f) as centimeters on a page, but this requires some coordinate conversion capabilities.
On Wed, 15 Dec 2004 10:58:37 -0500, Michael Walter <michael.walter@gmail.com> wrote:
How about GUIs which simply support floating point coordinates natively? I read that Cocoa uses floats for coordinates, and I would wildly guess that Avalon will make use if float vectors, as well (at least if the fancy 3D integration is remotely useful ;-).
Cocoa does indeed support float values natively. Regards, Reece

How about GUIs which simply support floating point coordinates natively? I read that Cocoa uses floats for coordinates, and I would wildly guess that Avalon will make use if float vectors, as well (at least if the fancy 3D integration is remotely useful ;-).
Cheers, Michael
Quartz in general uses floats (since it is a vector based system). So, even if we were to use Carbon as the primary interface, we'd still want floats for Mac work. Jared

"John Torjo" <john.lists@torjo.com> wrote
As a side-node, I'm moderately against having float coordinates. Why would you think int is not enough?
I would have thought that both types would be required dependent on the type of 'space' you are in. When working in pixels or 'device units', integers are an obvious choice ie at very low level. Each pixel is then visualised as a rectangular tile in a grid. The object (eg a window) is closely associated with the grid and the 'gridness' may well be taken into account when manipulating the object , which is specifically designed to 'live' only within the grid. However there are obvious cases (drawing a circle) where an analogue space is a better choice to represent the object. Scrolling and scaling are other factors A more complete framework would have UDT's rather than ints, representing pixels, as well as other types representing inches, millimetres as used in (say) CSS and (I think) SVG etc, which would allow automatic conversion (runtime for pixels) of one measure to another. It would also allow precise control over the semantics of converting. I have been using united types in this way for some time ( from my physical quantities library) and find it much more convenient and pleasant ( I make very little use of device units directly. There is always a transform to get to the device layer) and certainly dont miss the terseness of ints or reals, especially when reviewing the code. I have not implemented a pixel type as yet but I think it would be well worth while., although it would all need to be part of a cohesive 'space' system, probably with transforms for moving from one type of space to another. The type of unit would play a part in representing a particular view of space, either device space or logical space) A 'C compatible' alternative to units as types is an enum parameter representing the units in functions using units. (In both units and in transforms MS GDI+ is worth looking at. I think it takes the enum approach to units). Together with the point/size issue coordinate systems are in the set of primitives that are the building blocks of a 'space system'. like ints, doubles and maths are the building blocks a numeric system. regards Andy Little

Andy Little wrote:
"John Torjo" <john.lists@torjo.com> wrote
As a side-node, I'm moderately against having float coordinates. Why would you think int is not enough?
I would have thought that both types would be required dependent on the type of 'space' you are in. When working in pixels or 'device units', integers are an obvious choice ie at very low level. Each pixel is then visualised as a rectangular tile in a grid. The object (eg a window) is closely associated with the grid and the 'gridness' may well be taken into account when manipulating the object , which is specifically designed to 'live' only within the grid. However there are obvious cases (drawing a circle) where an analogue space is a better choice to represent the object. Scrolling and scaling are other factors
A more complete framework would have UDT's rather than ints, representing pixels, as well as other types representing inches, millimetres as used in (say) CSS and (I think) SVG etc, which would allow automatic conversion (runtime for pixels) of one measure to another. It would also allow precise control over the semantics of converting.
I think that the simplest way to do this is to have a coordinate_type UDT that specifies either float, long or a special type (like the one above). This type would then provide: long to_long() const; float to_float() const; This allows you to provide the necessary conversions (e.g. millimeters to pixels) and not worry whether the OS uses long/int or float values. The position, size and area types are then built using coordinate_type, where coordinate_type will provide conversion as necessary. One problem with this is how do you specify the coordinate_type used by the position/size types. If you do it via a macro definition you introduce binary incompatibility. If you use a template parameter, you will need to have a template decleration wherether you use the position/size, e.g.: template< typename CoordType > inline void move( const area< CoordType > & a ); which makes the implementation more complex, IMHO.
Together with the point/size issue coordinate systems are in the set of primitives that are the building blocks of a 'space system'. like ints, doubles and maths are the building blocks a numeric system.
Agreed. Though would it be better to have something like: class float_space { float val; public: long to_long() const{ return long( val ); } float to_float() const{ return val; } public: template< typename CoordType > float_space( CoordType ct ): val( ct.to_long()) { } }; class millimeter_space { ... template< typename CoordType > millimeter_space( CoordType ct ): val( from_float( ct.to_float())) { } }; template< typename CoordType > struct position_type { CoordType x, y; template< typename ConvType > position( ConvType a, ConvType b ): x( a ), y( b ); }; typedef position_type< float_space > position; Though I am not sure if this would work. Regards, Reece

"Reece Dunn" <msclrhd@hotmail.com> wrote in message news:BAY101-DAV14300DA4E52BA9F3F31320A0AE0@phx.gbl...
Andy Little wrote:
"John Torjo" <john.lists@torjo.com> wrote
As a side-node, I'm moderately against having float coordinates. Why would you think int is not enough?
I would have thought that both types would be required dependent on the type of 'space' you are in. When working in pixels or 'device units', integers are an obvious choice ie at very low level. Each pixel is then visualised as a rectangular tile in a grid. The object (eg a window) is closely associated with the grid and the 'gridness' may well be taken into account when manipulating the object , which is specifically designed to 'live' only within the grid. However there are obvious cases (drawing a circle) where an analogue space is a better choice to represent the object. Scrolling and scaling are other factors
A more complete framework would have UDT's rather than ints, representing pixels, as well as other types representing inches, millimetres as used in (say) CSS and (I think) SVG etc, which would allow automatic conversion (runtime for pixels) of one measure to another. It would also allow precise control over the semantics of converting.
I think that the simplest way to do this is to have a coordinate_type UDT that specifies either float, long or a special type (like the one above). This type would then provide:
long to_long() const; float to_float() const;
This allows you to provide the necessary conversions (e.g. millimeters to pixels) and not worry whether the OS uses long/int or float values.
Despite my previous remarks regarding automatic conversions, after reviewing what I have done on this previously I now conjecture that the two types of space (device space and logical space) have very different properties and their types cannot be directly compared against each other eg using operator < without some subtleties ( I now remember this is the reason that I havent completed a 'pixel' type). There needs to be a device available, to provide the 'context' of pixels_per_inch() or whatever, however, by changing the device mode( screen resolution) or the device itself( display <--> printer)) ,the comparison of two constants, one of each type, may give different results at different times. I am not sure that is a wise move! (I have always ended up using physical units for very much the above reasons and contrive to keep device units as a low level implementation detail.. It is a major reason that I ended up looking for and eventually writing a physical quantities library, to solve the problem once and for all! )
The position, size and area types are then built using coordinate_type, where coordinate_type will provide conversion as necessary.
One problem with this is how do you specify the coordinate_type used by the position/size types. If you do it via a macro definition you introduce binary incompatibility. If you use a template parameter, you will need to have a template decleration wherether you use the position/size, e.g.:
template< typename CoordType > inline void move( const area< CoordType > & a );
which makes the implementation more complex, IMHO.
How about defining one set of types which stands as the boost::gui abstraction user level type at a distinct layer above the OS ( and Maybe use a UDT, because you have complete control over the semantics of conversions if they are necessary, whereas you really dont with inbuilts without taking more drastic steps, though this does depend on the whole approach I guess) and apply whatever is necessary per operating system by actual conversion at some lower layer rather than by typedefs which differ dependent on the particular operating system... IOW a sort of encapsulation.
Together with the point/size issue coordinate systems are in the set of primitives that are the building blocks of a 'space system'. like ints, doubles and maths are the building blocks a numeric system.
Agreed.
[snip code commented above] Continuing on my old theme from several previous posts I think that convincing the user of the benefits of using a logical coordinate system, rather than using device coordinates is at the heart of this and honestly makes life so much simpler.Ultimately a pixel is simply not well enough defined ( How big is a pixel?) . However once the device is removed then something needs to replace it, which is a well thought out logical coordinate system. Rather than the crude approach I have taken recently in declaring types as physical quantities( eg length::mm ... which causes issues as to runtime scale changeing from mm to in for example), I have been recently thinking more in terms of using some sort of transform object, basically inspired by MS GDI+. A transform object at the level of the application( for example) could then be used to convert to logical coordinates in a (say) application window size event under control of the user, for example. I also wonder if a window is not , from a coordinate/space/ drawing viewpoint, just another graphics element and should follow the same graphics element rules as the objects in the client area. I have had a brief look at the recent docs and am glad to see the docs progress. It would be interesting to see Concept definitions of eg a button, drop down etc. IOW what is the 'minimalist essence of button' etc...:-) regards Andy Little

Andy Little wrote:
"Reece Dunn" <msclrhd@hotmail.com> wrote in message news:BAY101-DAV14300DA4E52BA9F3F31320A0AE0@phx.gbl...
Andy Little wrote:
"John Torjo" <john.lists@torjo.com> wrote
As a side-node, I'm moderately against having float coordinates. Why would you think int is not enough?
I would have thought that both types would be required dependent on the type of 'space' you are in. When working in pixels or 'device units', integers are an obvious choice ie at very low level. Each pixel is then visualised as a rectangular tile in a grid. The object (eg a window) is closely associated with the grid and the 'gridness' may well be taken into account when manipulating the object , which is specifically designed to 'live' only within the grid. However there are obvious cases (drawing a circle) where an analogue space is a better choice to represent the object. Scrolling and scaling are other factors
A more complete framework would have UDT's rather than ints, representing pixels, as well as other types representing inches, millimetres as used in (say) CSS and (I think) SVG etc, which would allow automatic conversion (runtime for pixels) of one measure to another. It would also allow precise control over the semantics of converting.
I think that the simplest way to do this is to have a coordinate_type UDT that specifies either float, long or a special type (like the one above). This type would then provide:
long to_long() const; float to_float() const;
This allows you to provide the necessary conversions (e.g. millimeters to pixels) and not worry whether the OS uses long/int or float values.
Despite my previous remarks regarding automatic conversions, after reviewing what I have done on this previously I now conjecture that the two types of space (device space and logical space) have very different properties and their types cannot be directly compared against each other eg using operator < without some subtleties ( I now remember this is the reason that I havent completed a 'pixel' type). There needs to be a device available, to provide the 'context' of pixels_per_inch() or whatever, however, by changing the device mode( screen resolution) or the device itself( display <--> printer)) ,the comparison of two constants, one of each type, may give different results at different times. I am not sure that is a wise move! (I have always ended up using physical units for very much the above reasons and contrive to keep device units as a low level implementation detail.. It is a major reason that I ended up looking for and eventually writing a physical quantities library, to solve the problem once and for all! )
Hmm. This is a complex issue! It makes sense to have some sort of metric_type that supports pixels, percentages, picas/points, millimeters and inches. As you hint at, these need a device to resolve or convert. In general, you will only want to manipulate a value using one specific metric type (e.g. specifying a font in points). You only really need to perform conversions when evaluating a value (e.g. when drawing a line from two coordinates). However, there may be a need for conversions in other areas, e.g. when getting the size that a string will take when rendered to a device using a specific font, you may want this to be in inches.
The position, size and area types are then built using coordinate_type, where coordinate_type will provide conversion as necessary.
One problem with this is how do you specify the coordinate_type used by the position/size types. If you do it via a macro definition you introduce binary incompatibility. If you use a template parameter, you will need to have a template decleration wherether you use the position/size, e.g.:
template< typename CoordType > inline void move( const area< CoordType > & a );
which makes the implementation more complex, IMHO.
How about defining one set of types which stands as the boost::gui abstraction user level type at a distinct layer above the OS ( and Maybe use a UDT, because you have complete control over the semantics of conversions if they are necessary, whereas you really dont with inbuilts without taking more drastic steps, though this does depend on the whole approach I guess) and apply whatever is necessary per operating system by actual conversion at some lower layer rather than by typedefs which differ dependent on the particular operating system... IOW a sort of encapsulation.
This is the thinking I am now making w.r.t. the metric type.
Together with the point/size issue coordinate systems are in the set of primitives that are the building blocks of a 'space system'. like ints, doubles and maths are the building blocks a numeric system.
Agreed.
[snip code commented above]
Continuing on my old theme from several previous posts I think that convincing the user of the benefits of using a logical coordinate system, rather than using device coordinates is at the heart of this and honestly makes life so much simpler.
It should be possible to select whether you want to use logical coordinates (picas/points, millimeters, inches) or device coordinates (pixels).
Ultimately a pixel is simply not well enough defined ( How big is a pixel?) . However once the device is removed then something needs to replace it, which is a well thought out logical coordinate system.
I see the advantages of this approach and am working on supporting logical coordinate systems (especially for graphics), but it should also be possible to use device coordinates (e.g. for specifying component positions and sizes). I am aware of problems with specifying component positions, which is where some basic layout engines are essential, and am working toward being able to implement them.
Rather than the crude approach I have taken recently in declaring types as physical quantities( eg length::mm ... which causes issues as to runtime scale changeing from mm to in for example), I have been recently thinking more in terms of using some sort of transform object, basically inspired by MS GDI+. A transform object at the level of the application( for example) could then be used to convert to logical coordinates in a (say) application window size event under control of the user, for example.
I will need to take a look at this.
I also wonder if a window is not , from a coordinate/space/ drawing viewpoint, just another graphics element and should follow the same graphics element rules as the objects in the client area.
I can see the advantages of this approach, but you need to take into account native-vs-custom drawn components.
I have had a brief look at the recent docs and am glad to see the docs progress.
:)
It would be interesting to see Concept definitions of eg a button, drop down etc. IOW what is the 'minimalist essence of button' etc...:-)
I am working on this. I have implementations of buttons and need to document their properties: push buttons, 2-state and 3-state check boxes and radio buttons/groups. Regards, Reece

Reece Dunn wrote:
Andy Little wrote:
Despite my previous remarks regarding automatic conversions, after reviewing what I have done on this previously I now conjecture that the two types of space (device space and logical space) have very different properties and their types cannot be directly compared against each other eg using operator < without some subtleties ( I now remember this is the reason that I havent completed a 'pixel' type). There needs to be a device available, to provide the 'context' of pixels_per_inch() or whatever, however, by changing the device mode( screen resolution) or the device itself( display <--> printer)) ,the comparison of two constants, one of each type, may give different results at different times. I am not sure that is a wise move! (I have always ended up using physical units for very much the above reasons and contrive to keep device units as a low level implementation detail.. It is a major reason that I ended up looking for and eventually writing a physical quantities library, to solve the problem once and for all! )
Hmm. This is a complex issue! It makes sense to have some sort of metric_type that supports pixels, percentages, picas/points, millimeters and inches. As you hint at, these need a device to resolve or convert.
In general, you will only want to manipulate a value using one specific metric type (e.g. specifying a font in points). You only really need to perform conversions when evaluating a value (e.g. when drawing a line from two coordinates). However, there may be a need for conversions in other areas, e.g. when getting the size that a string will take when rendered to a device using a specific font, you may want this to be in inches.
Taking a look at the CSS3 module on values and units (http://www.w3.org/TR/2001/WD-css3-values-20010713/), we have the following unit types: px (pixels) -- pixel units relative to the resolution of the viewing device. CSS3 gives a recommendation for rescaling to various devices (e.g. printer). in (inches) mm (millimeters) cm (centimeters) pt (points) pc (picas) % (percentage) sf (scalefactor) -- a multiplier for the size value em -- 'font-size' of the relevant font ex -- x-height of the relevant font Here, the CSS3 units em and ex are not really relevant because we have no font property to use to calculate the relative em/ex values. Looking at the values, it is possible to split them into 3 groups: * pixels -- device-specific unit size * inches -- logical unit size * scalefactor -- relative unit size All values are reducible to one of the three groups: pixels: 1px = 1px inches: 1in = 25.4mm = 2.54cm = 72pt = 6pc using the relationships: 1in = 2.54cm 1cm = 10mm 1pt = 1/72in 1pc = 12pt scalefactor: 1sf = 100% Now the problem is conversion between pixels, inches and scalefactor. scalefactor <--> pixels: required = max px sf --> px: px = max * sf px --> sf: sf = px / max scalefactor <--> inches required = max in sf --> in: in = max * sf in --> sf: sf = in / max pixels <--> inches required = pixels-per-inch (ppi) px --> in: in = px / ppi in --> px: px = in * ppi The above max px and max in can be reduced to max in since it is possible to convert max in --> max px, Thus we have: metric convert_to ( metric val, metric::type to, float max, float ppi ); Thoughts? Comments? Regards, Reece

Andy Little wrote:
"John Torjo" <john.lists@torjo.com> wrote
As a side-node, I'm moderately against having float coordinates. Why would you think int is not enough?
A more complete framework would have UDT's rather than ints, representing pixels, as well as other types representing inches, millimetres as used in (say) CSS and (I think) SVG etc, which would allow automatic conversion (runtime for pixels) of one measure to another. It would also allow precise control over the semantics of converting.
Is there a compelling reason for specifying an arithmetic type for coordinates? Or put another way, is there a disadvantage to leaving the coordinate type entirely opaque? A related situation from another problem domain is the time_t. While it is specified to be arithmetic, it may as well be opaque, as its representation is unspecified. In retrospect, would requiring it to be a particular type or representation been beneficial? Note that the return type of difftime() is double. The STL is another source of experience, where nearly everything is of an unspecified type, and often unspecified representation. In general, I think this vagueness in specification has led to a flexability that gives C++ a unique advantage over other similar languages. The recently reviewed conversions library also may be a useful source of experience with regards to this issue. I think the decision on the representation of coordinates is an extremely important one--one that might doom a library to ultimate obsoletion if decided wrongly. As Boost is meant to be a model of _the C++ way_, future libraries may also be inclined to specify in the manner Boost does. It's very important to remain forward-looking, thinking not, "What sort of pixel representation do today's GUIs use?" but rather "Will tomorrow's GUI be based on pixels?" Aaron W. LaFramboise

* Aaron W. LaFramboise <aaronrabiddog51@aaronwl.com> [2004-12-16 23:18]:
Andy Little wrote:
"John Torjo" <john.lists@torjo.com> wrote
As a side-node, I'm moderately against having float coordinates. Why would you think int is not enough?
A more complete framework would have UDT's rather than ints, representing pixels, as well as other types representing inches, millimetres as used in (say) CSS and (I think) SVG etc, which would allow automatic conversion (runtime for pixels) of one measure to another. It would also allow precise control over the semantics of converting.
I think the decision on the representation of coordinates is an extremely important one--one that might doom a library to ultimate obsoletion if decided wrongly. As Boost is meant to be a model of _the C++ way_, future libraries may also be inclined to specify in the manner Boost does. It's very important to remain forward-looking, thinking not, "What sort of pixel representation do today's GUIs use?" but rather "Will tomorrow's GUI be based on pixels?"
What about todays printer? Is that based on pixels? If I were to go to the trouble to create an GUI that rendered diagrams, I'd probably to to the touble to print those diagrams. I'd like to use the same algorithm to render to the screen and to the printer, simply swap out the device context. -- Alan Gutierrez - alan@engrm.com

Alan wrote:
* Aaron W. LaFramboise <aaronrabiddog51@aaronwl.com> [2004-12-16 23:18]:
Andy Little wrote:
"John Torjo" <john.lists@torjo.com> wrote
As a side-node, I'm moderately against having float coordinates. Why would you think int is not enough?
A more complete framework would have UDT's rather than ints, representing pixels, as well as other types representing inches, millimetres as used in (say) CSS and (I think) SVG etc, which would allow automatic conversion (runtime for pixels) of one measure to another. It would also allow precise control over the semantics of converting.
I think the decision on the representation of coordinates is an extremely important one--one that might doom a library to ultimate obsoletion if decided wrongly. As Boost is meant to be a model of _the C++ way_, future libraries may also be inclined to specify in the manner Boost does. It's very important to remain forward-looking, thinking not, "What sort of pixel representation do today's GUIs use?" but rather "Will tomorrow's GUI be based on pixels?"
What about todays printer? Is that based on pixels?
Printers are based on "dots per inch", e.g. a 600dpi printer. These dots can be seen as pixels, but the CSS documentation has information about converting screen pixels to other devices (e.g. printers) such that a pixel consists of 3 dots on a 300dpi printer and 5 dots on a 600dpi printer.
If I were to go to the trouble to create an GUI that rendered diagrams, I'd probably to to the touble to print those diagrams.
I'd like to use the same algorithm to render to the screen and to the printer, simply swap out the device context.
The Microsoft MFC library takes this approach and, IMHO, it is the best way to go. The problem is that with the MFC: * conversion between "metric spaces" (inches, pixels, picas) is not handled by the library, making it hard to say "draw a circle at (2in, 3.7in) with a radius of 2cm". * the way the library manages graphical objects and selecting a graphical object on a canvas is *way* off base! Anyway, I have started work on a metric type, available in the latest update to: http://uk.geocities.com/msclrhd/gui/gui.zip Be warned, though, that this is experimental. It provides conversion between the types that are directly convertable (e.g. points to inches). I have yet to work out how to properly handle conversions between the base types (pixels, inches and scalefactor). In principle, this is easy, given: * ppi: pixels per inch * max: maximum length of the object to which the metric value is bound we have pixels = inches * ppi = scale * max:px = scale * max:in * ppi inches = pixels / ppi = scale * max:in = scale * max:px / ppi scale = ? These values are dependant on the device being targetted. They are also dependant on the orientation of the metric (x-axis or y-axis). So how do we resolve the metric values? The best solution I can see is have a resolve_metric function on a device, such that: metric device::resolve_metric( metric, type, orientation ); it takes the metric and returns that metric with the units specified by type given the orientation. For example: p.x = dev.resolve_metric( p.x, metric::pixels, device::x_axis ); p.y = dev.resolve_metric( p.y, metric::pixels, device::y_axis ); This will convert the point p into pixels for the device specified by dev. Helper functions should be included to convert points, sizes and rects, e.g.: dev.resolve( val, metric::pixels, device::x_axis ); // metric dev.resolve( pt, metric::pixels ); // point dev.resolve( sz, metric::pixels ); // size dev.resolve( rc, metric::pixels ); // rect So, why the term device? A device (screen, printer, etc.) is an object that can perform graphical operations that render graphical content to it. The device can be queried for information relating to it (e.g. the size of a block of text or the number of pixels per inch along the y-axis). A canvas is an area that can be drawn on. It is possible to get a canvas for a device (allowing you to, for example, send a graphical image to a printer). Likewise, it is possible to get the device associated with the canvas (allowing you to perform metric conversions). The library update also includes some experimental work on basic graphics components (font) that I am using to compute the size of several widgets. The idea being that this can be plugged into a layout manager. The flow layout *does not work* at the moment and the whole layout mechanism may be subject to change. However, the widgets are fairly stable and usable. I have included buttons (push, checked (2 and 3 state), radio button/group), labels, textbox (textfield, textarea and password), along with a calendar widget that is MS-specific (I think). I intend on supporting a table control like the Java JTable component, with a TableModel-style interface. The link to the code is: http://uk.geocities.com/msclrhd/gui/gui.zip Regards, Reece

* Reece Dunn <msclrhd@hotmail.com> [2004-12-21 05:59]:
The link to the code is: http://uk.geocities.com/msclrhd/gui/gui.zip
How do I build this? I've built Boost on Win32 (with errors in the serialization library). I'd like to just cd to the gui directory and run bjam but it asks for a boost-build.jam file. Suggestions? Do I need to learn how to write a boost-build.jam file? -- Alan Gutierrez - alan@engrm.com

Alan Gutierrez wrote:
* Reece Dunn <msclrhd@hotmail.com> [2004-12-21 05:59]:
The link to the code is: http://uk.geocities.com/msclrhd/gui/gui.zip
How do I build this?
You need to configure Boost.Build v2. You will also need to update the source since I have modified the build files to use BOOST_ROOT to reference Boost.Signals and Boost.DateTime.
I've built Boost on Win32 (with errors in the serialization library). I'd like to just cd to the gui directory and run bjam but it asks for a boost-build.jam file.
boost-build.jam is used by BBv2. See http://www.boost.org/doc/html/bbv2/installation.html for setup instructions. You will also need to setup boost/tools/build/v2/user-config.jam. You also need to have BOOST_ROOT in either the environment variables or in the Jamfile configuration. To get the library working with gcc, you need to uncomment the <toolset>gcc: line and edit the location of libcomctl32.a.
Suggestions? Do I need to learn how to write a boost-build.jam file?
See the BBv2 docs for setting it up (see above). The new code update contains a few bug fixes, an update to the layout manager logic and a working version of the flow layout (although this does not yet wrap around controls). Regards, Reece

Alan Gutierrez wrote:
* Reece Dunn <msclrhd@hotmail.com> [2004-12-21 05:59]:
The link to the code is: http://uk.geocities.com/msclrhd/gui/gui.zip
How do I build this?
You need to configure Boost.Build v2. You will also need to update the source since I have modified the build files to use BOOST_ROOT to reference Boost.Signals and Boost.DateTime.
I've built Boost on Win32 (with errors in the serialization library). I'd like to just cd to the gui directory and run bjam but it asks for a boost-build.jam file.
For starters, I've put the code here so I can work with it and keep it in sync with your work: https://engrm.com/svn/boost/ You can get to it using Subversion. http://subversion.tigris.org/ I can keep it in sync as if I were vendor tracking, or I could give you a login. -- Alan Gutierrez - alan@engrm.com

* Reece Dunn <msclrhd@hotmail.com> [2004-12-21 18:36]:
Alan Gutierrez wrote:
* Reece Dunn <msclrhd@hotmail.com> [2004-12-21 05:59]:
The link to the code is: http://uk.geocities.com/msclrhd/gui/gui.zip
How do I build this?
You need to configure Boost.Build v2. You will also need to update the source since I have modified the build files to use BOOST_ROOT to reference Boost.Signals and Boost.DateTime.
I've built Boost on Win32 (with errors in the serialization library). I'd like to just cd to the gui directory and run bjam but it asks for a boost-build.jam file.
boost-build.jam is used by BBv2. See http://www.boost.org/doc/html/bbv2/installation.html for setup instructions. You will also need to setup boost/tools/build/v2/user-config.jam. You also need to have BOOST_ROOT in either the environment variables or in the Jamfile configuration.
To get the library working with gcc, you need to uncomment the <toolset>gcc: line and edit the location of libcomctl32.a.
Suggestions? Do I need to learn how to write a boost-build.jam file?
See the BBv2 docs for setting it up (see above).
The new code update contains a few bug fixes, an update to the layout manager logic and a working version of the flow layout (although this does not yet wrap around controls).
I've configured Boost.Build, edited the file locations in Jamfile.v2, and it now builds, no errors, but executables do not run. They fail with a ddl resolution error. The ddl sought is: MSVCP80.ddl I've searched my drive and I can't find it. I build boost using the free Visual C++ 2003, and built your work using cygwin gcc. I'm assuming that running the build using the gcc tool set caused the signals and date_time libraries to be compiled with gcc. Otherwise, I'll look here for problems. I'm re-installing Cygwin with Cygwin Python in order to build a complete Boost using Cygwin gcc. -- Alan Gutierrez - -alan@engrm.com

* Alan Gutierrez <alan-boost@engrm.com> [2004-12-21 23:50]:
* Reece Dunn <msclrhd@hotmail.com> [2004-12-21 18:36]:
Alan Gutierrez wrote:
* Reece Dunn <msclrhd@hotmail.com> [2004-12-21 05:59]:
The link to the code is: http://uk.geocities.com/msclrhd/gui/gui.zip
How do I build this?
You need to configure Boost.Build v2. You will also need to update the source since I have modified the build files to use BOOST_ROOT to reference Boost.Signals and Boost.DateTime.
I've built Boost on Win32 (with errors in the serialization library). I'd like to just cd to the gui directory and run bjam but it asks for a boost-build.jam file.
boost-build.jam is used by BBv2. See http://www.boost.org/doc/html/bbv2/installation.html for setup instructions. You will also need to setup boost/tools/build/v2/user-config.jam. You also need to have BOOST_ROOT in either the environment variables or in the Jamfile configuration.
To get the library working with gcc, you need to uncomment the <toolset>gcc: line and edit the location of libcomctl32.a.
Suggestions? Do I need to learn how to write a boost-build.jam file?
See the BBv2 docs for setting it up (see above).
The new code update contains a few bug fixes, an update to the layout manager logic and a working version of the flow layout (although this does not yet wrap around controls).
I've configured Boost.Build, edited the file locations in Jamfile.v2, and it now builds, no errors, but executables do not run.
They fail with a ddl resolution error. The ddl sought is:
MSVCP80.ddl
I've searched my drive and I can't find it.
I build boost using the free Visual C++ 2003, and built your work using cygwin gcc. I'm assuming that running the build using the gcc tool set caused the signals and date_time libraries to be compiled with gcc. Otherwise, I'll look here for problems.
I'm re-installing Cygwin with Cygwin Python in order to build a complete Boost using Cygwin gcc.
Agony! I found that the executables were included in the gui.zip, and where not built when I ran my build. So, now I simply can't get them to build, but at least they are not linking to a ddl that doesn't exist on my system. I'm cd'ing to the devel directory and running bjam. I'm getting this: rawapi.cpp:7:28: boost/config.hpp: No such file or directory bin\gcc\debug\user-interface-gui\entry.o(.text+0x73): In function `_ZN5boost3gui3win10entry_dataC1EPci': /cygdrive/c/codearea/boost/trunk/gui/libs/devel/../../boost/gui/win/platform.hpp:121: undefined reference to `_InitCommonControlsEx@4' ..\bin\gcc\debug\link-static\user-interface-gui\libgui.a(button.o)(.text+0x47): In function `_ZN5boost3gui6widgetD0Ev': /cygdrive/c/codearea/boost/trunk/gui/libs/../boost/gui/object/widget.hpp:44: undefined reference to `_GetStockObject@4' ..\bin\gcc\debug\link-static\user-interface-gui\libgui.a(widget.o)(.text+0xaf): In function `_ZN5boost3gui6widgetD1Ev': /cygdrive/c/codearea/boost/trunk/gui/libs/../boost/gui/object/component.hpp: undefined reference to `_GetStockObject@4' ..\bin\gcc\debug\link-static\user-interface-gui\libgui.a(widget.o)(.text+0x1e5): In function `_ZN5boost3gui6widgetC1EP6HWND__RKNS0_3win12basic_stringIcEES8_NS4_11frame_styleE': /cygdrive/c/codearea/boost/trunk/gui/libs/src/win/widget.cpp:19: undefined reference to `_GetStockObject@4' ..\bin\gcc\debug\link-static\user-interface-gui\libgui.a(font.o)(.text+0xf6): In function `_ZNK5boost3gui8graphics6devicecvP5HDC__Ev': /cygdrive/c/codearea/boost/trunk/gui/libs/../boost/gui/graphics/font.hpp: undefined reference to `_SelectObject@8' ..\bin\gcc\debug\link-static\user-interface-gui\libgui.a(font.o)(.text+0x17c):/cygdrive/c/codearea/boost/trunk/gui/libs/../boost/gui/graphics/font.hpp: undefined reference to `_GetTextExtentPoint32A@16' ..\bin\gcc\debug\link-static\user-interface-gui\libgui.a(font.o)(.text+0x1ff):/cygdrive/c/codearea/boost/trunk/gui/libs/../boost/gui/graphics/font.hpp: undefined reference to `_SelectObject@8' ..\bin\gcc\debug\link-static\user-interface-gui\libgui.a(font.o)(.text+0x33c): In function `_ZN5boost3gui8graphics4fontC2ERKNS0_3win12basic_stringIcEEfm': /cygdrive/c/codearea/boost/trunk/gui/libs/src/win/graphics/font.cpp:26: undefined reference to `_CreateFontA@56' ..\bin\gcc\debug\link-static\user-interface-gui\libgui.a(font.o)(.text+0x414): In function `_ZN5boost3gui8graphics4fontC1ERKNS0_3win12basic_stringIcEEfm': /cygdrive/c/codearea/boost/trunk/gui/libs/src/win/graphics/font.cpp:26: undefined reference to `_CreateFontA@56' ..\bin\gcc\debug\link-static\user-interface-gui\libgui.a(font.o)(.text+0x446): In function `_ZN5boost3gui8graphics4fontD2Ev': /cygdrive/c/codearea/boost/trunk/gui/libs/src/win/graphics/font.cpp:41: undefined reference to `_DeleteObject@4' ..\bin\gcc\debug\link-static\user-interface-gui\libgui.a(font.o)(.text+0x488): In function `_ZN5boost3gui8graphics4fontD1Ev': /cygdrive/c/codearea/boost/trunk/gui/libs/src/win/graphics/font.cpp:41: undefined reference to `_DeleteObject@4' ..\bin\gcc\debug\link-static\user-interface-gui\libgui.a(font.o)(.text+0x4ca): In function `_ZN5boost3gui8graphics4fontD0Ev': /cygdrive/c/codearea/boost/trunk/gui/libs/src/win/graphics/font.cpp:41: undefined reference to `_DeleteObject@4' ..\bin\gcc\debug\link-static\user-interface-gui\libgui.a(device.o)(.text+0x4b): In function `_ZN5boost3gui8graphics6deviceC2ERKNS0_3win12basic_stringIcEE': /cygdrive/c/codearea/boost/trunk/gui/libs/src/win/graphics/device.cpp:13: undefined reference to `_CreateDCA@16' ..\bin\gcc\debug\link-static\user-interface-gui\libgui.a(device.o)(.text+0xa5): In function `_ZN5boost3gui8graphics6deviceC1ERKNS0_3win12basic_stringIcEE': /cygdrive/c/codearea/boost/trunk/gui/libs/src/win/graphics/device.cpp:13: undefined reference to `_CreateDCA@16' ..\bin\gcc\debug\link-static\user-interface-gui\libgui.a(device.o)(.text+0xd6): In function `_ZN5boost3gui8graphics6deviceD2Ev': /cygdrive/c/codearea/boost/trunk/gui/libs/src/win/graphics/device.cpp:18: undefined reference to `_DeleteDC@4' ..\bin\gcc\debug\link-static\user-interface-gui\libgui.a(device.o)(.text+0x118): In function `_ZN5boost3gui8graphics6deviceD1Ev': /cygdrive/c/codearea/boost/trunk/gui/libs/src/win/graphics/device.cpp:18: undefined reference to `_DeleteDC@4' ..\bin\gcc\debug\link-static\user-interface-gui\libgui.a(device.o)(.text+0x15a): In function `_ZN5boost3gui8graphics6deviceD0Ev': /cygdrive/c/codearea/boost/trunk/gui/libs/src/win/graphics/device.cpp:18: undefined reference to `_DeleteDC@4' collect2: ld returned 1 exit status -- Alan Gutierrez - -alan@engrm.com

Alan Gutierrez wrote:
* Reece Dunn <msclrhd@hotmail.com> [2004-12-21 05:59]:
The link to the code is: http://uk.geocities.com/msclrhd/gui/gui.zip
How do I build this?
I've built Boost on Win32 (with errors in the serialization library). I'd like to just cd to the gui directory and run bjam but it asks for a boost-build.jam file.
Suggestions? Do I need to learn how to write a boost-build.jam file?
Yes, but it's pretty trivial. Just put boost-build path/to/boost/tools/build/v1 ; or boost-build path/to/boost/tools/build/v2 ; in it, depending on whether you're using BBv1 (the official release) or BBv2 (prerelease). The space before the semicolon is important. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

* David Abrahams <dave@boost-consulting.com> [2004-12-22 15:25]:
Alan Gutierrez wrote:
* Reece Dunn <msclrhd@hotmail.com> [2004-12-21 05:59]:
The link to the code is: http://uk.geocities.com/msclrhd/gui/gui.zip
How do I build this?
I've built Boost on Win32 (with errors in the serialization library). I'd like to just cd to the gui directory and run bjam but it asks for a boost-build.jam file.
Suggestions? Do I need to learn how to write a boost-build.jam file?
Yes, but it's pretty trivial. Just put
boost-build path/to/boost/tools/build/v1 ;
or
boost-build path/to/boost/tools/build/v2 ;
in it, depending on whether you're using BBv1 (the official release) or BBv2 (prerelease). The space before the semicolon is important.
Yes. I figured this bit out. I noted in another post. This was daunting at first. It is conforting to see a ./configure, because I know exactly where to go from there. There were confusing errors because I mistook an executable in Reece's gui.zip for a generated executable, and the error messages made absolutely no sense. It really threw me. Now that that issue has been resolved, Boost.Build is beginning to explain itself. -- Alan Gutierrez - alan@engrm.com

* Reece Dunn <msclrhd@hotmail.com> [2004-12-21 05:59]:
Alan wrote:
* Aaron W. LaFramboise <aaronrabiddog51@aaronwl.com> [2004-12-16 23:18]:
Andy Little wrote:
"John Torjo" <john.lists@torjo.com> wrote
As a side-node, I'm moderately against having float coordinates. Why would you think int is not enough?
A more complete framework would have UDT's rather than ints, representing pixels, as well as other types representing inches, millimetres as used in (say) CSS and (I think) SVG etc, which would allow automatic conversion (runtime for pixels) of one measure to another. It would also allow precise control over the semantics of converting.
I think the decision on the representation of coordinates is an extremely important one--one that might doom a library to ultimate obsoletion if decided wrongly. As Boost is meant to be a model of _the C++ way_, future libraries may also be inclined to specify in the manner Boost does. It's very important to remain forward-looking, thinking not, "What sort of pixel representation do today's GUIs use?" but rather "Will tomorrow's GUI be based on pixels?"
What about todays printer? Is that based on pixels?
Printers are based on "dots per inch", e.g. a 600dpi printer. These dots can be seen as pixels, but the CSS documentation has information about converting screen pixels to other devices (e.g. printers) such that a pixel consists of 3 dots on a 300dpi printer and 5 dots on a 600dpi printer.
This means that integers are still appropriate then. Still, I'm imagining that choosing a specific point representation is near sighted. The thought you are putting into effective conversions between different point units is important. In the CSS world, designers like to use the em unit to design interfaces that can scale cleanly to different resolutions. I'd like to see the Boost library include the concept of relative units as well as absolute units. It would help me to implement CSS using the GUI library.
If I were to go to the trouble to create an GUI that rendered diagrams, I'd probably to to the touble to print those diagrams.
I'd like to use the same algorithm to render to the screen and to the printer, simply swap out the device context.
The Microsoft MFC library takes this approach and, IMHO, it is the best way to go. The problem is that with the MFC:
* conversion between "metric spaces" (inches, pixels, picas) is not handled by the library, making it hard to say "draw a circle at (2in, 3.7in) with a radius of 2cm".
No good.
* the way the library manages graphical objects and selecting a graphical object on a canvas is *way* off base!
Fine. I've never liked MFC, the few minutes I've spent with it where agony.
Anyway, I have started work on a metric type, available in the latest update to:
As soon as I get things to compile, I'll comment on this.
So, why the term device? A device (screen, printer, etc.) is an object that can perform graphical operations that render graphical content to it. The device can be queried for information relating to it (e.g. the size of a block of text or the number of pixels per inch along the y-axis). A canvas is an area that can be drawn on.
The canvas is a hardware abstraction layer? It can be implemented once and devices can plug into it using adptor interfaces. The canvas could be generic type, and the template parameters are things like the preferred metric? I'm assuming that the canvas contains all of the drawing functions, like line_to and such. -- Alan Gutierrez - alan@engrm.com

* Reece Dunn <msclrhd@hotmail.com> [2004-12-21 05:59]:
Alan wrote:
* Aaron W. LaFramboise <aaronrabiddog51@aaronwl.com> [2004-12-16 23:18]:
Andy Little wrote:
"John Torjo" <john.lists@torjo.com> wrote
As a side-node, I'm moderately against having float coordinates. Why would you think int is not enough?
A more complete framework would have UDT's rather than ints, representing pixels, as well as other types representing inches, millimetres as used in (say) CSS and (I think) SVG etc, which would allow automatic conversion (runtime for pixels) of one measure to another. It would also allow precise control over the semantics of converting.
I think the decision on the representation of coordinates is an extremely important one--one that might doom a library to ultimate obsoletion if decided wrongly. As Boost is meant to be a model of _the C++ way_, future libraries may also be inclined to specify in the manner Boost does. It's very important to remain forward-looking, thinking not, "What sort of pixel representation do today's GUIs use?" but rather "Will tomorrow's GUI be based on pixels?"
What about todays printer? Is that based on pixels?
Printers are based on "dots per inch", e.g. a 600dpi printer. These dots can be seen as pixels, but the CSS documentation has information about converting screen pixels to other devices (e.g. printers) such that a pixel consists of 3 dots on a 300dpi printer and 5 dots on a 600dpi printer.
If I were to go to the trouble to create an GUI that rendered diagrams, I'd probably to to the touble to print those diagrams.
I'd like to use the same algorithm to render to the screen and to the printer, simply swap out the device context.
Anyway, I have started work on a metric type, available in the latest update to: http://uk.geocities.com/msclrhd/gui/gui.zip
The library update also includes some experimental work on basic graphics components (font) that I am using to compute the size of several widgets. The idea being that this can be plugged into a layout manager. The flow layout *does not work* at the moment and the whole layout mechanism may be subject to change.
However, the widgets are fairly stable and usable. I have included buttons (push, checked (2 and 3 state), radio button/group), labels, textbox (textfield, textarea and password), along with a calendar widget that is MS-specific (I think). I intend on supporting a table control like the Java JTable component, with a TableModel-style interface.
My design for a C++ GUI library would being with creating an flow component that could render XML + CSS. The flow component would flow blocks. Blocks would contain text, images, or other objects. If a block changed size, the flow component would reflow immediately. This is basically what web designers work with in a modern browser like KHTML or Mozilla. I'm far more interested in creating a component of this nature, than another set of gray box wrappers. Initially, I figured I'd stop short of attempting to create a 2d canvas, something that would be a outlet for vector graphics like SVG or flash. The components in the GUI library could then be implemented using the flow compnent. This would mean skipping platform specific widget library, and implementing an cross-platform widget library using this flow component, combining blocks, effects, and images, to create what ever look and feel is desired. The look and feel could be specified by designers somewhat simply using XML + CSS. You'd get skinnable applications. Swing took the route of defining look and feel in Java, and foroging native components. I'd like to make it much easier to implement the look and feel. Create all the widgets using the flow component, and with C++, you'd not pay too dear a penalty for forgoing native components. Native components are welcome, of course, so long as they play nice the canvas. (Win32 GDI objects do not.) A huge benefit, too, is that if someone implements a the device class for their device, they could turn to Boost to have a ready Windowing library. So, I'm going to get working on a flow component... -- Alan Gutierrez - alan@engrm.com

My design for a C++ GUI library would being with creating an flow component that could render XML + CSS.
The flow component would flow blocks. Blocks would contain text, images, or other objects. If a block changed size, the flow component would reflow immediately.
This is basically what web designers work with in a modern browser like KHTML or Mozilla. I'm far more interested in creating a component of this nature, than another set of gray box wrappers.
Initially, I figured I'd stop short of attempting to create a 2d canvas, something that would be a outlet for vector graphics like SVG or flash.
The components in the GUI library could then be implemented using the flow compnent.
This would mean skipping platform specific widget library, and implementing an cross-platform widget library using this flow component, combining blocks, effects, and images, to create what ever look and feel is desired. The look and feel could be specified by designers somewhat simply using XML + CSS.
You'd get skinnable applications.
Swing took the route of defining look and feel in Java, and foroging native components. I'd like to make it much easier to implement the look and feel.
Create all the widgets using the flow component, and with C++, you'd not pay too dear a penalty for forgoing native components.
Native components are welcome, of course, so long as they play nice the canvas. (Win32 GDI objects do not.)
A huge benefit, too, is that if someone implements a the device class for their device, they could turn to Boost to have a ready Windowing library.
So, I'm going to get working on a flow component...
The real benefit is that every widget now gets to have multi-lingual support as a native capability. And you also get word wrapping, hyphenation, etc.. on every widget...! Mathew

* Mathew Robertson <mathew.robertson@redsheriff.com> [2004-12-22 00:27]:
My design for a C++ GUI library would being with creating an flow component that could render XML + CSS.
The flow component would flow blocks. Blocks would contain text, images, or other objects. If a block changed size, the flow component would reflow immediately.
This is basically what web designers work with in a modern browser like KHTML or Mozilla. I'm far more interested in creating a component of this nature, than another set of gray box wrappers.
Initially, I figured I'd stop short of attempting to create a 2d canvas, something that would be a outlet for vector graphics like SVG or flash.
The components in the GUI library could then be implemented using the flow compnent.
This would mean skipping platform specific widget library, and implementing an cross-platform widget library using this flow component, combining blocks, effects, and images, to create what ever look and feel is desired. The look and feel could be specified by designers somewhat simply using XML + CSS.
You'd get skinnable applications.
Swing took the route of defining look and feel in Java, and foroging native components. I'd like to make it much easier to implement the look and feel.
Create all the widgets using the flow component, and with C++, you'd not pay too dear a penalty for forgoing native components.
Native components are welcome, of course, so long as they play nice the canvas. (Win32 GDI objects do not.)
A huge benefit, too, is that if someone implements a the device class for their device, they could turn to Boost to have a ready Windowing library.
So, I'm going to get working on a flow component...
The real benefit is that every widget now gets to have multi-lingual support as a native capability.
And you also get word wrapping, hyphenation, etc.. on every widget...!
Yes. I get giddy. You get a multi-lingual, bidi wrapping, rich text editor, or get a table full of them. It really seems like the right way to do things, and I'm inspired by web designers that roll their own very complex controls using XHTML divs and spans. I'm also looking at how Swing is trying to find an XML expression for itself. XML langauges for Swing have sprouted like mushrooms. Any new GUI toolset should design a declarative layout into itself, not attach one later. http://www.jeasy.de/ http://www.ultrid.com/ https://jdnc.dev.java.net/ Note that I'm not touting XML, per se, but the CSS flow model. I'd imagine that one might declare the composition of their interface using Python, or that a very clever generic programming library could be developed, like Spirit. XHTML would be obvious, but not necessary. In fact, I think some of the Swing XML implementations miss the point. The flow layout plus the bubbling event model is what makes XHTML programming so simple. I don't think this is a replacement for MVC. I think it is a great way to implement the VC part. In writing about it, I've come to see this as a VC implementation option; a component that implements CSS flow. CSS flow only. I'd not take it one step further and make it an implementation of SVG, since XHTML + CSS address the issues you've hit on, bidi word wrapping, hypenation, and since most controls are some flavor of text box. An vector graphics component would be a separate animal, or specialization of the species that addressed a different set of problems. -- Alan Gutierrez - alan@engrm.com

* Alan Gutierrez <alan-boost@engrm.com> [2004-12-21 22:03]:
* Reece Dunn <msclrhd@hotmail.com> [2004-12-21 05:59]:
Alan wrote:
* Aaron W. LaFramboise <aaronrabiddog51@aaronwl.com> [2004-12-16 23:18]:
Andy Little wrote:
"John Torjo" <john.lists@torjo.com> wrote
As a side-node, I'm moderately against having float coordinates. Why would you think int is not enough?
A more complete framework would have UDT's rather than ints, representing pixels, as well as other types representing inches, millimetres as used in (say) CSS and (I think) SVG etc, which would allow automatic conversion (runtime for pixels) of one measure to another. It would also allow precise control over the semantics of converting.
I think the decision on the representation of coordinates is an extremely important one--one that might doom a library to ultimate obsoletion if decided wrongly. As Boost is meant to be a model of _the C++ way_, future libraries may also be inclined to specify in the manner Boost does. It's very important to remain forward-looking, thinking not, "What sort of pixel representation do today's GUIs use?" but rather "Will tomorrow's GUI be based on pixels?"
What about todays printer? Is that based on pixels?
Printers are based on "dots per inch", e.g. a 600dpi printer. These dots can be seen as pixels, but the CSS documentation has information about converting screen pixels to other devices (e.g. printers) such that a pixel consists of 3 dots on a 300dpi printer and 5 dots on a 600dpi printer.
If I were to go to the trouble to create an GUI that rendered diagrams, I'd probably to to the touble to print those diagrams.
I'd like to use the same algorithm to render to the screen and to the printer, simply swap out the device context.
Anyway, I have started work on a metric type, available in the latest update to: http://uk.geocities.com/msclrhd/gui/gui.zip
The library update also includes some experimental work on basic graphics components (font) that I am using to compute the size of several widgets. The idea being that this can be plugged into a layout manager. The flow layout *does not work* at the moment and the whole layout mechanism may be subject to change.
However, the widgets are fairly stable and usable. I have included buttons (push, checked (2 and 3 state), radio button/group), labels, textbox (textfield, textarea and password), along with a calendar widget that is MS-specific (I think). I intend on supporting a table control like the Java JTable component, with a TableModel-style interface.
My design for a C++ GUI library would being with creating an flow component that could render XML + CSS.
The flow component would flow blocks. Blocks would contain text, images, or other objects. If a block changed size, the flow component would reflow immediately.
I'm going to get working on a flow component...
A flow component would occupy a rectangle. It would represent a view port to a larger rectangle. It woud devide the larger rectange into rectangles. These divisions nest, so there would be a recursive structure. I suppose this outer rectangle contians a list of divisions that are sorted on the z-axis. The divisons are sorted on their y axis. A reference can be kept to the first division exposed by the view port, so that redrawing and hit testing can skip the divisions above the view port, and move through the list to the point where either the view port, or the division ends. Divisions can be buffered, so that if one division changes size, the divisions that beneith it can reflow without having to be redrawn. I'm not sure if divisions are kept in the standard containers, or if they are linked to each other explicitly, or through a special data structure. I'm not familiar with STL and such, but there would be a desire to to say, insert a division after this division frequently. The divisions in the list of divisions flow either to the right or the previous division or beneith the previous division. ? Except in the cases where they are floating within the previous division, or other divisions piror, as in CSS float. CSS float translates to this structure, but the XML elements are going to be in a different order that the division objects. Any one of the divisions may be resized at any point, causing all of the divisions following it to reflow. Any one of the divisions may accept text input. This is a plubble structure that can be inserted as a division into a division, essentially a decoration. It is a text division? It contians a string of text. The string of text is a simple string, and is likely to be loosly coupled, perhaps M in MVC. It also contains a data structure that devides that text into strands of formating and another data structure that divides the text into futher divisions, which represent the inline formatting of the text. This ought to work for text directions other than the one I am familiar with. In this way, the text is broken up into ribbons, which indicate the styling applied to the text, and also into divisions, which indicate flow of the lines of text. -- Alan Gutierrez - alan@engrm.com

Reece Dunn wrote:
If I were to go to the trouble to create an GUI that rendered diagrams, I'd probably to to the touble to print those diagrams.
I'd like to use the same algorithm to render to the screen and to the printer, simply swap out the device context.
The Microsoft MFC library takes this approach and, IMHO, it is the best way to go.
That's okay for simple things, but for any serious printing work you need to know you're talking to a printer. For example, you may need to embed postscript in your output stream. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

* David Abrahams <dave@boost-consulting.com> [2004-12-22 15:13]:
Reece Dunn wrote:
If I were to go to the trouble to create an GUI that rendered diagrams, I'd probably to to the touble to print those diagrams.
I'd like to use the same algorithm to render to the screen and to the printer, simply swap out the device context.
The Microsoft MFC library takes this approach and, IMHO, it is the best way to go.
That's okay for simple things, but for any serious printing work you need to know you're talking to a printer. For example, you may need to embed postscript in your output stream.
I'd like to look at how OS X is able to make a PDF of everything. Observing that capability lead me to believe that you could simply swap out the underlying device. Is this still a way to go, using the same algorithm, but adding an object to represent the context, screen, printer, etc.? -- Alan Gutierrez - alan@engrm.com

Alan Gutierrez wrote:
* David Abrahams <dave@boost-consulting.com> [2004-12-22 15:13]:
Reece Dunn wrote:
If I were to go to the trouble to create an GUI that rendered diagrams, I'd probably to to the touble to print those diagrams.
I'd like to use the same algorithm to render to the screen and to the printer, simply swap out the device context.
The Microsoft MFC library takes this approach and, IMHO, it is the best way to go.
That's okay for simple things, but for any serious printing work you need to know you're talking to a printer. For example, you may need to embed postscript in your output stream.
I'd like to look at how OS X is able to make a PDF of everything. Observing that capability lead me to believe that you could simply swap out the underlying device.
Maybe on OSX, where IIUC everything is already DPS-based, you can do something like that. In my experience with the models used by Windows and MacOS 9 and earlier, it doesn't work out that way. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

On Thu, Dec 23, 2004 at 12:11:08PM -0500, Alan Gutierrez wrote:
I'd like to look at how OS X is able to make a PDF of everything. Observing that capability lead me to believe that you could simply swap out the underlying device.
That's easy: you start with a vector description of *everything* and plug a rasterizer where needed. This vector description in Quartz is called DPS: Display PostScript. This gives you the gimmicks you see on MacOS X, for example window minimization and maximization effects. You just need to start with a rectangle, and subdivide the edges, and apply some transformation to them. Then you can use algebraic grid generation to compute the inner grid. And now you only need to apply the grid transformation to the elements of the window. Marcelo

* Marcelo E. Magallon <mmagallo@debian.org> [2004-12-28 16:42]:
On Thu, Dec 23, 2004 at 12:11:08PM -0500, Alan Gutierrez wrote:
I'd like to look at how OS X is able to make a PDF of everything. Observing that capability lead me to believe that you could simply swap out the underlying device.
That's easy: you start with a vector description of *everything* and plug a rasterizer where needed. This vector description in Quartz is called DPS: Display PostScript.
This gives you the gimmicks you see on MacOS X, for example window minimization and maximization effects. You just need to start with a rectangle, and subdivide the edges, and apply some transformation to them. Then you can use algebraic grid generation to compute the inner grid. And now you only need to apply the grid transformation to the elements of the window.
Thinking: ui -> paint ui -> box ui -> component One can create components by using resource handles, one can draw boxes using a very simple device, or work with vector graphics. Different abstractions of drawing. On weak devices components or boxes are the best you will get. On better devices you can paint. On Palm you might do box<render_as<native>>, simple aaboxes. On OS X you do box<render_as<native>>, native vector described aaboxes. On Win32 you do box<render_as<paint>>, for a software implementation of vector described aaboxes. Same with components. component<render_as<resource>> component<render_as<box>> component<render_as<paint>> button<render_as<native>> on OS X is Aqua. button<render_as<native>> on Win32 requires an HWND. button<render_as<paint>> on Win32 is "light-weight". Where canvas is a vector graphics library: canvas<render_as<box>> causes a compile time error. Current thinking: ui -> window ui -> box ui -> paint ui -> component ui -> form ui -> grid ui -> document ui -> canvas . . . (binding, validation, accesibility, mvp, etc.) What I'm driving at. A wide, but shallow, scope. -- Alan Gutierrez - alan@engrm.com

Reece Dunn wrote:
Hi All,
I have been working on revising my GUI library that is currently in
...
Also, the target operating system places design problems on creating a generic interface. For example, Windows supports char * and wchar_t * versions of its API, but the version that should be used depends on whether you are targetting Windows 9x or NT based systems. Windows
The vast majority of textual data in my W2K applications tend to be char. I'd hate to have to explicitly convert to wchar_t for every API textual call. Jeff

Jeff Flinn wrote:
Reece Dunn wrote:
Hi All,
I have been working on revising my GUI library that is currently in
...
Also, the target operating system places design problems on creating a generic interface. For example, Windows supports char * and wchar_t * versions of its API, but the version that should be used depends on whether you are targetting Windows 9x or NT based systems. Windows
The vast majority of textual data in my W2K applications tend to be char. I'd hate to have to explicitly convert to wchar_t for every API textual call.
The same is true when using std::string. I have provided a helper string class that will perform implicit conversion so that on unicode builds, char strings are converted to wchar_t strings and vice versa for ascii builds. This allows you to do: gui::main_frame mainfrm( "GUI Application" ); // ... and have it build on either configuration of the windows API. It also makes the code more portable, since I am not sure what string type the other APIs use as default (I presume most are char *), and doing: gui::main_frame mainfrm( TEXT( "GUI Application" )); is non-portable and ugly. The library currently works on msvc 8.0 and 7.1. I am currently getting an undefined reference to _WinMain@16 error on gcc 3.3 and on cw 9.2 I am getting: ### mwcc Compiler: # In: ..\..\..\..\boost\boost\function\function_template.hpp # From: ..\src\win\radio_group.cpp #----- # 473: on::has_empty_target(addressof(f))) { # Error: ^ # ambiguous access to overloaded function I am going to look into fixing these errors I also intend on supporting the alternate Boost.Signal syntax for broken compilers so that msvc 7.0 and borland 5.6 can be supported. I am getting far too many errors on msvc 6.5 and will not provide support for it. I have made a few more modifications, available here: http://uk.geocities.com/msclrhd/gui/gui.zip Regards, Reece

you might consider adding operator[] to point and size also, consider defining area in terms of 2 points, and adding operator[] to that, too regards, michael toksvig "Reece Dunn" <msclrhd@hotmail.com> wrote in message news:BAY101-F20FDD5860C530B8D6ADE17A0AC0@phx.gbl...
Hi All,
I have been working on revising my GUI library that is currently in the sandbox. The motivation for doing this was Andy Little's comment that most GUI libraries start from a particular operating system and then abstract its interface, providing work-arounds for other GUI systems.
There are several considerations to make with a GUI library. For insatance, it should be possible to support GUI interfaces on portable devices (e.g. Palm Pilot/PalmOS) and terminal devices (like is done with the VIM editor). With these devices, code needs to be written to provide common components such as buttons.
Also, the target operating system places design problems on creating a generic interface. For example, Windows supports char * and wchar_t * versions of its API, but the version that should be used depends on whether you are targetting Windows 9x or NT based systems. Windows also requires each component type to be registered before you can create an instance of it.
Each operating system has different arguments that it passes when an event is generated, containing data relating to that event. Consideration must be made to allow events to be written generically, but also allow you to hook into OS-specific events and get OS-specific data.
With all this in mind, how do you design a GUI library for C++? Although a GUI component exists on the screen and is drawn on that screen, the components and graphics elements should be kept seperate, since it is primarily the OSs role to render a component. There are shared elements (mostly the position, size and area types) and the graphics layer should allow for graphics-based events to be handled by the components library.
Taking a look at how C++ is designed, it is predominantly data orientated. That is, C++ allows you to create new data types that fit into the language via operator overloading. The STL provides collections of data and algorithms for manipulating those collections. Terminal-based applications are supported by I/O streams that allow you to send data out and read data in.
I have taken this as the primary design feature when implementing the GUI components. Thus, each component has an event to signal user interaction (ondatachanged, onselectionchanged, onpressed) and data that is associated with the component.
The first thing that comes to mind when reading "data that is associated with the component" is data binding. I think it is a mistake to build data binding directly into the component architecture. The reason for this is twofold:
You would need to use templates to bind the different data objects to the control which makes it harder to implement the controls in a platform-independant way and can lead to code bloat. Also, consider having a textbox widget that you use to enter the age. Having:
gui::textbox< long > age;
How does the textbox perform the conversion? By storing the data as a string, the user can extract the information on data collection like this:
long age = boost::lexical_cast< long >( age_input.get_text());
or
long age = ::atol( age_input.get_text());
Another thing to take into account is when an input field has a validity based on other component values. For example, the valitity of a dates day field is dependant on month and year. In this instance, it is best to put all the validation logic in the base component and extract the data to a date class such as Boost.DateTime's date.
A component has a size and position, as well as visibility (visible or hidden) and enabled/disabled states. The component should make it easy to interoperate with native API.
The majority of the current proposals (mine included) have taken the approach of providing native interoperability with the OS-specific data structures. This is very difficult to maintain properly and support generic code because of the different names of the data elements, types used (long or float) and whether an area is (position + size) or (top-left + bottom-right). Also, most OSs have (0,0) being the top-left corner, but MacOS has (0,0) being bottom-left.
With this in mind, I have taken a drastic approach: do not provide native interoperability for size, position and area. I have designed them as:
struct position{ float x; float y; }; struct size{ float dx; float dy; }; struct area { float top; float left; float width; float height; };
This means that the interface must convert these to the native representations and vise versa.
The current implementation (Windows specific at this time) can be found at: http://uk.geocities.com/msclrhd/gui/gui.zip
Thoughts? Comments?
Regards, Reece
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
participants (14)
-
Aaron W. LaFramboise
-
Alan
-
Alan Gutierrez
-
Andy Little
-
David Abrahams
-
Hajo Kirchhoff
-
Jared McIntyre
-
Jeff Flinn
-
John Torjo
-
Marcelo E. Magallon
-
Mathew Robertson
-
michael toksvig
-
Michael Walter
-
Reece Dunn