Issue 3-9, March 4, 1998

Be Engineering Insights: Fun with Tabs and Sliders

By Robert Chinn

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 = new BTabView( 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 100
B_WIDTH_FROM_WIDEST—bases all tab widths on the
                       longest tab name
B_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 = new BSlider ( BRect (0,0,100,10),
    "slider",
    "Some value:",
    new BMessage('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_color color;
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()
{
  char msg[32];

  sprintf(msg, "The current value is: %i.", Value());
  return msg;
}

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.

class DemoSlider : public BSlider {
public:
    DemoSlider(BRect frame, char *label, BMessage *msg,
      int32 min, int32 max, thumb_style t);
    ~DemoSlider();

    char* UpdateText() const;

private:
  char* fStatus;
};

DemoSlider::DemoSlider(BRect frame, char *label,
  BMessage *msg, int32 min, int32 max, thumb_style t)
  : 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 me
  fStatus = (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();
    return fStatus;
  } else
    return NULL;
}

static void
DoMe()
{
  //   construct a simple window
  BWindow* a_window = new BWindow(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 label
  BTabView* tab_container = new BTabView(
    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
  float contents_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 view
  BView* bg_1 = new BView(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 you
  bg_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 300
  BSlider* block_thumb_slider = new BSlider(slider_rect,
    "block thumb", "Slider Label", new BMessage('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 10
  block_thumb_slider->SetKeyIncrementValue(10);

  //  add some labels
  block_thumb_slider->SetLimitLabels("minimum", "maximum");

  //  add some hash marks
  block_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 tabview
  tab_container->AddTab(bg_1);

  //  construct a second view
  BView* bg_2 = new BView(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 slider
  DemoSlider* triangle_thumb_slider =
    new DemoSlider(slider_rect,"", new BMessage('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_color c;
  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 active
  tab_container->Select(0);

  //   make the window visible
  a_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.


Making Money

By Dave Johnson

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.


Developers' Workshop: Welcome to x86

By Doug Wright

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.

Endianness

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.

Filesystem and Resource File Incompatibility

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 BMessages 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.

Compiling

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

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.

Stephen Makes Life Easier

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.

The BeDC

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 Experience

By Jean-Louis Gassée

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.

Creative Commons License
Legal Notice
This work is licensed under a Creative Commons Attribution-Non commercial-No Derivative Works 3.0 License.