When you receive Release 3 of the BeOS, among other grander and more
important advances, you'll find that the Interface Kit now contains two
more classes, BTabView
and
BSlider
. Since they're new I'd like to
introduce them and discuss how to use them.
A tabview is a simple container object that allows you to separate and present information in a clean, easily accessed fashion. Instead of using a pop-up menu to toggle between pages of information, you can use a tabview to provide an interface that presents topics and focused information to the user.
BTabView
is a simple and pretty much self-contained class that doesn't
require a lot of maintenance once it has been constructed. In its most
basic form there are only two things you need to do to use a BTabView
:
construct it and add views to it.
BTabView
*tab_container
= newBTabView
(BRect
(0,0,320,240), "tab container",B_WIDTH_AS_USUAL
,B_FOLLOW_LEFT
|B_FOLLOW_RIGHT
,B_WILL_DRAW
|B_NAVIGABLE
);
This constructs an empty tab container and shows no tabs. As with most
other simple BView
derivatives, you pass in the
frame
, name
,
resizing_mode
, and view flags
.
The only other item in the constructor for a
tabview is the button_width
parameter, which configures the width of each
tab that the tabview presents. This parameter has three options, which
are identical to those used in a BAlert
:
B_WIDTH_AS_USUAL
—sets the tab width to the default of 100B_WIDTH_FROM_WIDEST
—bases all tab widths on the longest tab nameB_WIDTH_FROM_LABEL
—bases each tab width on its related name
To add a tab to the tabview you need to call the following:
tab_container
->AddTab
(tab_view_1
,NULL
);
where tab_view_1
is a BView
that contains the rest of the objects you
want to present in this "page." The name of the tab associated with the
page is the name of the view that you add in the AddTab()
call. Also, the
location of the view to be added, if set to 0,0, will be the left edge of
the tab, just below and inside the box drawn by the tabview.
The optional parameter to the AddTab()
method, in this case NULL
, is a BTab
pointer. The BTab
class is a simple non-view class that simply draws to a
target view. Using this parameter you can override the default BTab
object and perform custom drawing for each individual tab.
As you make successive calls to AddTab()
,
tab_container
->AddTab
(tab_view_2
);tab_container
->AddTab
(tab_view_3
);tab_container
->AddTab
(tab_view_4
);
more tabs are added to the tabview. When the user clicks on any of these
tabs, the view it is associated with is added to the tabview via
AddChild()
, and made visible, while the previous visible view is hidden as
a result of RemoveChild()
. That's all it takes to make a tabview functional
in an application.
The second class I'd like to introduce is BSlider
.
Like BTabView
, this is
also a simple class, based on BControl
, that presents itself as a slider
control. As with any other BControl
-based objects the construction is
quite simple:
BSlider
*slider
= newBSlider
(BRect
(0,0,100,10), "slider", "Some value:", newBMessage
('slde'), 0, 255,B_BLOCK_THUMB
);
The first four parameters are the standard BControl
parameters:
frame
,
name
, label
, and message
.
The message is sent when you move the slider
and release it. The fifth and sixth parameters are the minimum
and
maximum
values for the slider. The last parameter is the thumb style,
which can be set to one of two built-in thumbs, a rectangle (as used in
the Keyboard preferences) or a triangle (as used in the Fonts
preferences).
If you take a look at the VirtualMemory preferences application you'll notice that the bar color to the left of the thumb is different from the color to the right. To accomplish this, simply do the following:
rgb_colorcolor
;color
.red
=color
.green
= 102;color
.blue
= 152;color
.alpha
= 255;slider
->UseFillColor
(true
, &color
);
The callback method UpdateText()
provides live updating of information. In
this method you can call Value()
or
Position()
to obtain information relating
to the slider and return a string of text to present to the user; in its
default state it simply returns NULL
.
char*DemoSlider
::UpdateText
() { charmsg
[32];sprintf
(msg
, "The current value is: %i.",Value
()); returnmsg
; }
The slider can have as many as four different labels or none. The
standard BControl
label is drawn at the top
left; set via SetLimitLabels()
(the minimum and maximum labels) in the bottom left and right; and the
string returned from UpdateText()
in the top right. If any of these labels
is set to NULL
, it will not be drawn.
To recap, here is a bit of code that builds two sliders in a two-tab
tabview. The second slider is a custom slider to demonstrate use of the
UpdateText()
callback.
classDemoSlider
: publicBSlider
{ public:DemoSlider
(BRect
frame
, char *label
,BMessage
*msg
, int32min
, int32max
, thumb_stylet
);~DemoSlider
(); char*UpdateText
() const; private: char*fStatus
; };DemoSlider
::DemoSlider
(BRect
frame
, char *label
,BMessage
*msg
, int32min
, int32max
, thumb_stylet
) :BSlider
(frame,"demo slider",label,msg, min, max, t) { // allocate some space for the string to be returned in // UpdateText. use malloc so that Pavel will yell at mefStatus
= (char*)malloc
(64); }DemoSlider
::~DemoSlider
() { if (fStatus
)free
(fStatus
); } // When the slider's Draw method is called, this method // will also be called. If its return value is non-NULL, // then it will be drawn with the rest of the slider char*DemoSlider
::UpdateText
() const { if (fStatus
&&Window
()->Lock
()) {sprintf
(fStatus
,"Current value is %i",Value
());Window
()->Unlock
(); returnfStatus
; } else returnNULL
; } static voidDoMe
() { // construct a simple windowBWindow
*a_window
= newBWindow
(BRect
(25, 25, 345, 165), "New Control Demo",B_TITLED_WINDOW
,B_NOT_ZOOMABLE
|B_NOT_RESIZABLE
); // construct a tabview // make the tab width based on the widest labelBTabView
*tab_container
= newBTabView
(BRect
(0, 0, 320, 140), "tab container",B_WIDTH_FROM_WIDEST
);a_window
->AddChild
(tab_container
); // do a quick calculation to determine the height of the // content region of the tabview floatcontents_height
=tab_container
->Bounds
().Height
() -tab_container
->TabHeight
();BRect
contents_rect
(0, 0,tab_container
->Bounds
().Width
(),contents_height
);BRect
slider_rect
(contents_rect
);slider_rect
.InsetBy
(25,25); // construct a view to hold the first control // the name of the tab associated with this view // will be the name of this viewBView
*bg_1
= newBView
(contents_rect
, "Slider with Block Thumb",B_FOLLOW_NONE
,B_WILL_DRAW
); // set the view to this control so that is blends in // with the tabview // set the alpha component so Hiroshi won't yell at youbg_1
->SetViewColor
(216,216,216,255); // construct a slider with a block thumb // the message that it will send will have a 'what' of 'blok' // the minimum setting will be 0, the maximum will be 300BSlider
*block_thumb_slider
= newBSlider
(slider_rect
, "block thumb", "Slider Label", newBMessage
('blok'), 0, 300,B_BLOCK_THUMB
); // if this slider has the focus (set by tabbing to it), // the left and right arrows will move it by 10block_thumb_slider
->SetKeyIncrementValue
(10); // add some labelsblock_thumb_slider
->SetLimitLabels
("minimum", "maximum"); // add some hash marksblock_thumb_slider
->SetHashMarkCount
(5);block_thumb_slider
->SetHashMarks
(B_HASH_MARKS_BOTH
);bg_1
->AddChild
(block_thumb_slider
); // make this view (and control) a tab of the tabviewtab_container
->AddTab
(bg_1
); // construct a second viewBView
*bg_2
= newBView
(contents_rect
, "Slider with Triangle Thumb",B_FOLLOW_NONE
,B_WILL_DRAW
);bg_2
->SetViewColor
(216,216,216,255); // construct a custom slider with a triangle thumb // when this slider is drawn, the text returned // from UpdateText will be drawn in the // upper right corner of the sliderDemoSlider
*triangle_thumb_slider
= newDemoSlider
(slider_rect
,"", newBMessage
('tri '), 1, 7,B_TRIANGLE_THUMB
);triangle_thumb_slider
->SetKeyIncrementValue
(1);triangle_thumb_slider
->SetLimitLabels
("one", "seven");triangle_thumb_slider
->SetHashMarkCount
(7);triangle_thumb_slider
->SetHashMarks
(B_HASH_MARKS_BOTTOM
); // set the fill for left of thumb color rgb_colorc
;c
.green
= 102;c
.red
= 102;c
.blue
= 152;triangle_thumb_slider
->UseFillColor
(true
,&c
);bg_2
->AddChild
(triangle_thumb_slider
);tab_container
->AddTab
(bg_2
); // the list of tabs is 0 based, make the first tab activetab_container
->Select
(0); // make the window visiblea_window
->Show
(); }
Both BSlider
and BTabView
are fairly simple. The goal was to make them
not difficult to use or overbearing and complex objects. I hope that both
of these objects suffice and that programmers find them useful. An
example of the use of BTabView
can be found in the Fonts preferences
application. Examples of BSlider
can be found in Keyboard, Mouse, and
many other preference applications.
Good news: The BeOS is beginning to be noticed in the PC press.
More good news: Most of the "media" companies I talk to tell me they realize that media applications will eventually HAVE TO be on the BeOS to be competitive, and sooner rather than later.
Every day it looks more and more like the BeOS will emerge as the OS of choice for media development. If you're writing a media application and you're reading this Newsletter, you are in the right place.
You're also in the right place to make money writing software that is not media-oriented. One good bet right now is developer tools: the BeOS for Intel offers you a fresh shot at the same developers you're trying to sell to right now. Another wide-open area to consider is utilities of all kinds.
Here are some tips on making money selling software for the BeOS:
Be offers BeOS software developers a unique opportunity to reach their potential market through our BeWare listings. The web orientation of our CDs and downloadable OS make it a safe bet that most BeOS users will visit the BeWare site. This immediate visibility to the user base of an OS is a new concept that gives BeOS software developers a terrific—and inexpensive—head start at reaching a market.
Need proof that this concept works? BeWare had 36,000 hits last week and 18,791 files were downloaded. Keep in mind that's for the Power Mac BeOS only, with the Mac at 2.6% market share.
So get something up on BeWare! Make sure that your BeWare listings are up to date, informative, benefit-oriented, and that they SELL your products. If you're not up on BeWare yet, you're missing out.
There's another reason to get your product up on BeWare: publishers are entering the BeOS market and they're looking for products and programmers. What better way to reach them than via BeWare? Read my article "How to Finish a Product," http://www.be.com/aboutbe/benewsletter/Issue98.html#Developer. Stop adding features and ship what you have to BeWare! (You can always put the rest in version 2.)
At your end of the sales process, do you have a web site ready? Your own web site is your primary BeOS sales tool after BeWare! The BeWare site will send many software-hungry customers your way, so you should have your web site ready to accommodate them. Is the entry page of your web site clear, informative, and sales oriented? Does your web site direct the customer to product information? Do you have clear, benefit-oriented descriptions of your products? Benefits, benefits, benefits—stress benefits. Repeat your message, repeatedly.
Do you have order forms? Do you accept credit cards? Do you quickly send the software to customers who order it? Do you sell through BeDepot? If you do, get the customers interested in your product and send them where they can place the order right now. Getting the order should be an immediate part of the process. The excitement you generate for your product will fade, so it's important to provide the ordering opportunity immediately.
If you're not sales-oriented, take heart. This isn't a huckster approach to ripping off the customer. Look at it as an opportunity to place your fine product in the hands of more and more people.
Acquiring a sales orientation is difficult for many of us. I came by mine the hard way in a past life running a software company. After years of struggling, we tried actually selling something to customers using direct mail, and learned that it works. It changed the culture of the company. Gosh, offering products to customers in a sales-oriented way actually works!
It's surprising how many smaller software companies don't understand that. I know how hard it was for me, coming from primarily an engineering background, to become sales-oriented. It seemed pushy, obnoxious, and aggressive but it turned out that it works. (Now I'm pushy, obnoxious, and aggressive, and I work...)
So before you get revolted at the thought of selling your product, remember that those sales types wouldn't be doing what they do if it didn't work. As much as you hate the thought, it might be a good idea to infect your offices with one of those sales types—checkered sport jacket, slick hair, suspenders, and all the rest—because if your background is engineering, the world of sales may be another planet to you, but it's very necessary to making money.
But wait, there's more! Accept this free gift as a token of my appreciation for reading this article! Check out the web sites of companies that are sales-oriented, and blatantly steal ideas from them. Two that come to mind are Intuit (http://www.intuit.com/) and Berkeley Systems (http://www.berksys.com/).
Here's a very important tip: Make the press aware of your products. My next article will discuss getting press for your products. The very best way to get people interested in your software is by getting press attention, so start thinking about it now and we'll compare notes. Getting press for your BeOS products helps us get the Be ball rolling, and that helps you, too.
This week we'd like to present a laundry list of issues you should be aware of when moving to the brave new world of x86 development.
Incompatibilities between the x86 and PowerPC releases stem primarily from the opposing endianness of the processors. This topic has been covered exhaustively in previous Newsletter articles. For specifics, reread:
"Swapping Bytes, Part III"
By Peter Potrebic - Issue 3-#8
"YABSA—Yet Another Byte-swapping Article"
By Bradley Taylor - Issue 2-#45
"Will Your DATA Look Like ATAD?"
By Bradley Taylor - Issue 2-#9
The new header support/ByteOrder.h
contains a slew of handy-dandy
functions and macros to help you sex, resex, and neuter your data.
Although we successfully eliminated many of the endian problems encountered in porting the BeOS to x86, there are still a few that will linger at least through Release 3.
The internal BFS structures are endian opposite on the different platforms: big-endian on PowerPC and little-endian on x86. We currently do not have any tools that allow a BeOS machine to read a disk in the opposite endian format. This does not mean there is no way to transfer information across platforms; ftp still works as advertised, and, when combined with zip, will even correctly transfer the filesystem attributes.
The BFS endian issues have to do with BFS's internal structures for storing data, not the data itself. If your data is endian-independent, it will be usable on both platforms without changes. Otherwise, you may have problems if you don't check the endianness of the data before using it.
The majority of the persistent data formats in the BeOS are endian-
independent; in particular, both filesystem attributes and flattened
BMessage
s are endian-agnostic. The resource file format is a notable
exception to this rule. You cannot use PowerPC resource files while
building a x86 application (and vice versa)—you need new x86 resources.
Release 3 ships with several tools to help translate resources, but their abilities are limited: They convert only a few resource types, and are unable to translate many of the data types found in a resource file. Custom resource formats, of course, need to be translated manually. In most cases, it's easier to create separate PowerPC and Intel resource files from scratch and use the appropriate one as needed.
We are working on solutions to both of these problems, but at this time we can't say exactly when they will be available.
The biggest change to compiling is in the creation of shared libraries
(and consequently add-ons). In the PowerPC world, symbols are exported
from a shared library through the use of the #pragma export on
and
#pragma export off
pair. Additionally, you don't have to do anything
special to import symbols.
The x86 release understands different semantics for importing and
exporting symbols. It is still necessary to explicitly export a symbol
from a library, but you also must explicitly import the symbol into your
applications. Importing symbols from add-ons doesn't change; the symbol
is still resolved with find_image_symbol()
. However, if you are linking
against a shared library, you need to import the symbols.
The Intel release uses the traditional x86 methods for importing and exporting symbols:
__declspec(dllexport) type name for exporting __declspec(dllimport) type name for importing
In both cases, type specifies what is being exported, and name specifies
its name. The new header file
BeBuild.h
selectively exports or imports
the system classes and global functions, depending on whether the
libraries are being built or linked against.
We recommend following a similar pattern in your own header files, rather than having separate header files for importing and exporting. Please see the "Moving from PR2 to Release 3: Development Layout" section of the Release 3 Release Notes for a more detailed look at this issue.
A related note: The Metrowerks x86 compiler allows the use of #pragma
export
and #pragma import
to export and import symbols on the x86.
However, we strongly recommend use of the more traditional (if ugly)
__declspec()
system, as it is more likely to be supported by future
compilers.
Finally, with the recent codification of the ANSI C++ spec, Metrowerks has removed the inherited keyword from their compilers. This is a good thing. If you use this keyword in your code, we strongly urge you to replace it with a specific call to the appropriate parent member. Meanwhile, you can use the compiler switch -pragma "def_inherited on" to accept the old method. This switch will not be supported indefinitely, so it's best to take the time and replace those calls to inherited.
Linking with shared libraries is a bit different on the x86. Instead of
linking with the library itself, you now link with a special
.LIB
file (a
"linkable library"). For example, you now link with the linkable library
libbe.so.LIB
, instead of the shared library
libbe.so
. The system-linkable
libraries may be found in /boot/develop/lib/x86
. On the PowerPC, nothing
changes: You still link with the shared library itself.
On a similar note, if you are linking against either the kernel (for
drivers) or the current application (for add-ons), you must link against
either _KERNEL_.LIB
or
_APP_.LIB
, as appropriate.
_KERNEL_.LIB
may be
found in the same directory as the other system linkable libraries, while
_APP_.LIB
must be culled from the appropriate application. The compiler
automatically generates a .LIB
file for an x86 image—be it an
application, a static library, or a dynamic library—if any symbols are
exported (via __declspec(export)
).
There are a few new objects in
/boot/develop/lib/x86
, notably
glue-noinit.a
, init_term_dyn.o
,
and start_dyn.o
. All programs need these
objects. Normally, you shouldn't notice them since they're pulled in
automatically by the linker. However, if you run into problems with
unresolved symbols, try explicitly linking these files into your object.
The same drill applies to the PowerPC release as well.
In an effort to make things easier for our developers, I've developed a fairly basic, but usable, cross-platform makefile. The current incarnation can be found at ftp://ftp.be.com/pub/samples/intro/obsolete/Makefile. This is a generic makefile that allows a developer to specify whether an application or static or shared library is being created; what files, libraries, and resources are needed to create it; and what its final name will be. This makefile will continue to be upgraded as time allows, and as needed.
If you are an experienced makefile builder, and you have suggestions on how to improve it, I'd like to hear from you. If you are unfamiliar with makefiles in general (as I was when I started this), take a look. They really aren't that terrible to deal with. Send all reports directly to Developer Support via the online form in the Registered Developer Area.
Finally, please realize that the Newsletter format doesn't permit an exhaustive look at all the issues arising from the x86 port of the BeOS. For a more thorough presentation, be sure to attend the BeDC, where two sessions will be devoted to the x86 port: Approaching a Cross Platform OS; and in the extended track, Working with Intel. Bring your comments, questions, and concerns to these sessions, and we'll try to get you the answers you need.
The Newton is no more. This is a little sad for the few people at Be who once worked on that project in an earlier life, people such as Bob Herold, Peter Potrebic, Steve Sakoman and yours truly. But we live on and we are grateful for a few lessons which found their way into our work here at Be.
The Newton story started late Spring of 1987. After successfully directing the engineering efforts resulting in the Mac Plus, the Mac SE and the Mac II (the Open Mac), Steve Sakoman sat in my office in the De Anza III building in Cupertino and calmly told me he was going to leave Apple.
To do what? To start a company that would build a new portable computer. The size of a notebook, you'd write on the screen with a stylus and the computer would recognize your handwriting. I asked Steve if he would hire me as a CEO for his venture, he said yes, and we started looking for money.
I'll cut a convoluted story to the known next milestone, we stayed at Apple, Steve started what became known as the Newton project in a building on Bubb Road. We liked the Newton concept very much, we saw the Newton as "scalable": the idea of a computing device capable of recognizing handwriting could be implemented, in theory, on a product as small as a checkbook, or as large as a drafting table or even a networked whiteboard.
Furthermore, the Newton concept did not threaten to cannibalize desktop sales. As a result, we could develop a complete hardware and software architecture and, if the market graft "took"—that is, if we succeeded in attracting enough developers and customers—we could mutate a version of the new platform into a more classical desktop product.
The latter thought was directed at our concern over the limitations of the Macintosh architecture and the perceived need to, first, develop a replacement in case it would age prematurely and, second, to do so without wrecking the existing desktop business, without, in other words, "osborning" the Mac.
We liked the Newton so much that when John Sculley gave me the benevolent physical and financial kick to get in business on my own, I offered to lead an effort to "claris" the Newton into an independent subsidiary. Benevolently again, the offer was turned down. Still, for several years, as we kept our work at Be under wraps, many were convinced we were developing some PDA, as the term gained currency after the Go/Eo, Winpad, Zoomer and finally Newton were announced.
We started collecting the benefits of the Newton's lessons early. One of several reasons we didn't start a PDA company was we had grown disenchanted with handwriting recognition. We had started to suspect recognition would never reach "transparency." By this I mean the kind of performance that never stands between you and your goal, your task. Most of the time, error correction on a hard disk or a CD is transparent, it takes place but stays out of the way. At Be, we decided our project would only integrate known technologies, there were enough other kinds of risk in it already.
The other lesson we learned, we hope, was setting expectations. The Newton was announced with the greatest of fanfares, with proclamations of trillion dollar turn-of-the-century markets. Imagine for a moment a different kind of announcement: This is from our advance technology division, this is only for the hardiest of explorers, this is not yet a product for the mainstream.
Instead of becoming the butt of Doonesbury cartoons, not necessarily bad publicity, the Newton could have iterated towards a nice PDA with the support of the early adopter community. In other words, the Surgeon General warnings and pocket protectors we associated with our product come from our concern to represent our product as we think it is, good genes, but not an adult yet, not ready for the mainstream.
We hope you'll join us at our Developer Conference in two weeks to check on the young OS's progress.