Table of Contents
BE EVENTS: I. Joint BUGs IRC with Be Inc. II. Be Developer Conference - Europe
I. JOINT BUGs IRC with BE INC. This Internet Relay Chat is for members of the Joint BeOS User Groups and Be Inc. The IRC will be hosted on newnet at irc.busprod.com(6667) #BeOS joint BUG IRC Members of the joint BUGs may obtain details from the president of their particular BUG or from Shannon (s_ndmn@yahoo.com).
II. BE DEVELOPER CONFERENCE - EUROPE
October 7-8, 1999 This fall Be Europe will be hosting a Be Developer Conference. Space is limitted, so sign up now and experience the splendor of a BeDC in Deutschland.
Registration is now open. Get more information here: <http://www.be.com/world/events/bedc/october1999/> BE DEVELOPER CLASSIFIEDS: BIAS Hiring Experienced Application Developer
BIAS Hiring Experienced Application Developer Berkley Integrated Audio Software, Inc. has an opportunity for an experienced application developer; Mac OS, Windows, or BeOS experience a plus. Hot on the heels of their recent announcement to bring Peak, their award-winning audio editor, to BeOS, BIAS is hiring an experienced developer to focus on BeOS development. Please send a letter of inquiry and a resume to: Steve Berkley, President <steve@bias-inc.com> For more info on Peak, please visit http://www.bias-inc.com BE ENGINEERING INSIGHTS: Hacking the Stack By Scott Barta sbarta@be.com
The lack of debugging tools on the BeOS often means that you Call stack tracing (like MALLOC DEBUG does for blocks) is Stack crawling inside your own program is made possible by a A limitation of MALLOC DEBUG is the fact that it doesn't The Kernel Kit provides a set of image functions intended to Given an image id obtained from get next image info, you can Responsible Be engineers always include some usable snippets
A call to init sym table() from main() is the all that is Return addresses located at a given depth in the stack are Be aware that GCC's -fomit-frame-pointer option will cause Once you have an address, you can use lookup symbol() to A quick look at the function shows that, given an address, That's about all there is to it. Feel free to use the code
BE ENGINEERING INSIGHTS: Font Sensitivity Training By Robert Chinn rudeboy@be.com
This article offers some tips and techniques for creating a clean, font-sensitive, consistent user interface. Putting together a good UI isn't difficult, but it requires a little extra thought about sizing and placement of UI elements and a basic understanding of how our view system works. To have a consistent interface you must first understand what the views will use for layout and placement. The BBox is the only Interface Kit class that, by default, sets its view font to be bold font; all other views use be plain font unless they're set otherwise. So -- what is be plain font or be bold font? In the first panel of the Fonts preference application you'll see the current system settings for the plain, bold, and fixed fonts the system is using. Next, open the Fonts.h interface file. Near the bottom of the file you'll find this: extern IMPEXP BE const BFont* be plain font; extern IMPEXP BE const BFont* be bold font; extern IMPEXP BE const BFont* be fixed font; You can use these three globals to reference the current fonts for each of the three system settings. Two items to note are calculating the height of a control and the width of text based on the desired font. You can do this easily by using float stringwidth = be plain font->StringWidth("some piece of text"); which will return the width necessary to draw "some piece of text" in whatever the current plain font might be. To calculate the font height, try using static float FontHeight(const BFont* font, bool full) { font height finfo; font->GetHeight(&finfo); float h = finfo.ascent + finfo.descent; if (full) h += finfo.leading; return h; } This will return the correct height necessary for all the text to be visible for any font. Please note that the font settings for the following examples aren't necessarily recommended, but are used here as an example of how settings affect view layout. We'll assume that these views have the following code as their parent, and that the code is added to a window: BBox* box = new BBox(Bounds(), "background", B FOLLOW ALL, B WILL DRAW | B FRAME EVENTS, B PLAIN BORDER); AddChild(box); Many classes in the Interface Kit size themselves based on the plain font setting, although some do not. Most initially use some basic default values for layout, and many of these values should be overridden to achieve a clean interface. Now then, let's take a look at a number of the Interface Kit classes. BStringView A BStringView is a simple view that displays static, noneditable text. It's often used to display information such as labels or the status of some process. Remember when you're using a BStringView that it requires adequate space, both width and height, to display completely any text that it might hold. To properly size a BStringView, try this: BRect frame(10, 10, 10 + be plain font->StringWidth("Just a string"), 10 + FontHeight(be plain font, true)); BStringView* stringview = new BStringView(frame, "string", "Just a string"); box->AddChild(stringview); If you do this the string will always be completely displayed to the user, regardless of the current plain font settings. BTextView A BTextView, unlike a BStringView, can be an editable text field for displaying multi-line text. As with sizing the BStringView, correct initial sizing of a BTextView can also be done quite easily: frame.Set(10, stringview->Frame().bottom+10, Bounds().Width()-10, stringview->Frame().bottom+10 + 3 + (3 * FontHeight(be plain font, true)) + 3); // // The text rect is inset a bit so that there // is a reasonable gutter surrounding the text // BRect textrect(frame); textrect.OffsetTo(0,0); textrect.InsetBy(2,2); BTextView* textview = new BTextView(frame, "text", textrect, B FOLLOW LEFT RIGHT | B FOLLOW TOP, B WILL DRAW); box->AddChild(textview); This creates a simple editable text area that displays three full lines. BTextControl, BMenuField A BTextControl is a mixed control; the left portion is a static label, the right portion is a field that allows text entry and can send a message notifying the host that the text has been modified. A BMenuField is similar, but has a pop-up menu on the right. As with the previous classes, sizing is important for display, but for this class, the height is set by the class once it is added to a parent. Note that both of these classes include a label that displays static text. Rather than just placing multiple BTextControls or BMenuFields with their left edges aligned, you can get a more pleasing effect by aligning the controls at their Divider, the line that divides the label from the actual control. Once again, you can accomplish this by doing some initial calculations and by understanding the controls themselves. const char* const kAnythingStr = "Anything"; const char* const kNumbersOnlyStr = "10 Numbers Only"; float maxlabelwidth = be bold font->StringWidth(kNumbersOnlyStr) + 5; float labelwidth = be plain font->StringWidth(kAnythingStr) + 5; // // based on the longest label "Anything" // simply calculate from that controls divider // to where a smaller label should start // frame.left = (10 + maxlabelwidth) - labelwidth; // // make this view relative to the last view added // it will resize itself vertically // so, just create a valid BRect // frame.top = textview->Frame().bottom + 10; frame.bottom = frame.top + 1; BTextControl* tc1 = new BTextControl(frame, "any text", kAnythingStr, kAnythingStr, NULL, B FOLLOW LEFT RIGHT | B FOLLOW TOP); box->AddChild(tc1); // // set the divider and alignment // so that it looks good // tc1->SetDivider( be plain font->StringWidth(kAnythingStr) + 5); tc1->SetAlignment(B ALIGN RIGHT, B ALIGN LEFT); // // once again, place the next view below the last // frame.top = tc1->Frame().bottom + 5; frame.bottom = frame.top + 1; frame.left = 10; // // calculate the actual width based on the // text and font // frame.right = be bold font->StringWidth(kNumbersOnlyStr) + 5 + 10 + (be bold font->StringWidth("0")*10) + 10; BTextControl* tc2 = new BTextControl(frame, "numbers only", kNumbersOnlyStr, "0987654321",NULL); box->AddChild(tc2); tc2->SetFont(be bold font); tc2->SetDivider( be bold font->StringWidth(kNumbersOnlyStr) + 5); tc2->SetAlignment(B ALIGN RIGHT, B ALIGN LEFT); // // here is a bit of extra code that // shows how to limit a BTextView to // a specific set of characters // BTextView* tv = tc2->TextView(); tv->SetMaxBytes(10); for (long i = 0; i < 256; i++) tv->DisallowChar(i); for (long i = '0'; i <= '9'; i++) tv->AllowChar(i); tv->AllowChar(B BACKSPACE); // and, now for a couple BMenuFields // // build up a sample menu // BPopUpMenu* menu = new BPopUpMenu("a simple menu"); menu->AddItem(new BMenuItem("First Item", NULL)); menu->AddItem(new BMenuItem("Second Item", NULL)); menu->ItemAt(0)->SetMarked(true); // // place this control relative to the BTextControls // frame.top = tc2->Frame().bottom + 10; frame.bottom = frame.top + 1; frame.left = (tc2->Frame().left + tc2->Divider()) - (be plain font->StringWidth("A Longer Label")+5); // // and, again, calculate the correct width based // on the text and font // frame.right = frame.left + be plain font->StringWidth("A Longer Label") + be plain font->StringWidth("Second Item") + 30; BMenuField* menubtn1 = new BMenuField(frame, "menu/menufield", "A Longer Label", menu); box->AddChild(menubtn1); menubtn1->SetDivider( be plain font->StringWidth("A Longer Label") + 5); // // and, create a second one // menu = new BPopUpMenu("a simple menu"); menu->AddItem(new BMenuItem("Some Item", NULL)); menu->AddItem(new BMenuItem("Another Item", NULL)); menu->ItemAt(1)->SetMarked(true); menu->SetFont(be bold font); frame.top = menubtn1->Frame().bottom; frame.bottom = frame.top + 1; frame.left = (menubtn1->Frame().left + menubtn1->Divider()) - (be bold font->StringWidth("Menu")+5); frame.right = frame.left + be bold font->StringWidth("Menu") + be plain font->StringWidth("Another Item") + 30; BMenuField* menubtn2 = new BMenuField(frame, "menu/menufield", "Menu", menu); box->AddChild(menubtn2); menubtn2->SetFont(be bold font); menubtn2->SetDivider( be bold font->StringWidth("Menu")+5); Not only will the dividers be aligned, but there will be no dead space to the left of the label. The effect is that only the label and the control will be clickable, resulting in a moderately cleaner UI. BButton A BButton is a simple push button. It's easy to create and use, but tricky to have it show its display label correctly. As with a BTextControl, a BButton's height is based on the current plain font. Its width, though, should be calculated and padded with respect to the plain font. // the default minimum width of a button used by Be // const float kMinimumButtonWidth = 75.0; const char* const kOkayStr = "Okay"; const char* const kLongStr = "Some extra long button name"; float width = be plain font->StringWidth(kOkayStr) + 20; frame.top = menubtn2->Frame().bottom + 10; frame.bottom = frame.top + 1; frame.left = 10; // // accommodate a longer width, depending on the text // and the font, else use the default minimum size // frame.right = frame.left + ((width > kMinimumButtonWidth) ? width : kMinimumButtonWidth); BButton* btn1 = new BButton(frame, "button", kOkayStr, NULL); box->AddChild(btn1); // // and, add another wider button // width = be bold font->StringWidth(kLongStr) + 20; frame.left = frame.right + 10; frame.right = frame.left + ((width > kMinimumButtonWidth) ? width : kMinimumButtonWidth); BButton* btn2 = new BButton(frame, "button", kLongStr, NULL); box->AddChild(btn2); btn2->SetFont(be bold font); BCheckBox, BRadioButton The last two controls I'll address are BCheckBox and BRadioButton. Both are standard and, like BButton, their height is sized appropriately, based on the current plain font. Note that to create a more intuitive UI, sizing the width appropriately will make your controls a bit cleaner. Once again, use StringWidth and some padding for the frame when creating these controls. frame.left = 10; frame.right = frame.left + 20 + be bold font->StringWidth("Bold RadioButton"); frame.top = btn2->Frame().bottom + 10; frame.bottom = frame.top+1; BRadioButton* rb1 = new BRadioButton(frame, "radio button", "Bold RadioButton", NULL); box->AddChild(rb1); rb1->SetFont(be bold font); frame.top = rb1->Frame().bottom; frame.bottom = frame.top + 1; frame.right = frame.left + 20 + be bold font->StringWidth("RadioButton"); BRadioButton* rb2 = new BRadioButton(frame, "radio button", "RadioButton", NULL); box->AddChild(rb2); rb2->SetFont(be bold font); // frame.top = rb1->Frame().top; frame.bottom = frame.top + 1; frame.left = rb1->Frame().right + 20; frame.right = frame.left + 20 + be plain font->StringWidth("CheckBox"); BCheckBox* cb1 = new BCheckBox(frame, "checkbox", "CheckBox", NULL); box->AddChild(cb1); frame.top = rb2->Frame().top; frame.bottom = frame.top + 1; frame.right = frame.left + 20 + be plain font->StringWidth("Longer CheckBox Title"); BCheckBox* cb2 = new BCheckBox(frame, "checkbox", "Longer CheckBox Title", NULL); box->AddChild(cb2); As with the labels for a BTextControl or BMenuField, the only portion of the CheckBox or BRadioButton that is clickable is now the label and the control itself. Notice that many of these examples use a previous control to initially place the next control. Doing this makes your layout sensitive to the font height; also, controls set up this way will not collide with each other upon display. Lastly, the window should flow with the font sensitivity of the views that it contains. Here, a basic heuristic is used to determine what the height and width should be: // // the height of the window will be relative // to the last control added, in this case the // last BCheckBox // the width of the window will be based on the // control that has its right edge furthest to // the right, in this case either the last // BCheckBox or the second BButton // float right = (cb2->Frame().right > btn2->Frame().right) ? cb2->Frame().right : btn2->Frame().right; ResizeTo(right + 10, cb2->Frame().bottom + 10); Add the above code to a window of an application and run it. All the controls will be visible and sized appropriately. The views themselves will not overrun their siblings and only the visible portions of the controls will be active. Now open the Fonts preference application and select any set of fonts, close the panel, and open the test application again. While the panel may be larger, or possibly smaller, the same criteria will hold true. So, why bother with these extra calculations and concerns? Simple -- to make your interface consistent and always usable. Since the user can configure his system in many ways, particularly the choice of fonts, applications should defer to the user's wishes.
DEVELOPERS' WORKSHOP: Pulse -- The Next Generation By Daniel Switkin switkin@be.com
BIT BY BIT: Opening Files By Stephen Beaulieu hippo@be.com
Rephrase inches towards usability. This week -- opening files from the command line in Terminal. To make each file open up in its own phrase window, type: You can find this version of Rephrase at: <ftp://ftp.be.com/pub/samples/tutorials/rephrase/rephrase0.1d2.zip> Rephrase 0.1d2
New Features Programming Concepts You access files in BeOS through the classes of the Storage Kit. Conceptually, the Storage Kit consists of two types of objects: those representing a location in a filesystem, and those representing the content at a specific location. The objects representing a location include:
The content at a specific location is represented by subclasses of BNode. This version of Rephrase deals with one such class, the BFile, and only with it's creation. The BFile is manipulated through the BTextView. For more detailed information on the Storage Kit or on BeOS installation see: <http://www-classic.be.com/documentation/be book/The%20Storage%20Kit/ index.html> or: <file:///boot/beos/documentation/Be%20Book/The%20Storage%20Kit/ index.html> BApplication has a hook function ArgvReceived() that passes in any command line arguments passed to the application. Rephrase interprets these arguments as a list of files to open. In ArgvReceived() Rephrase translates each file name to a BEntry, and if there is a file at that location, puts the appropriate entry ref in a B REFS RECEIVED message, which it passes to RefsReceived(). RefsReceived() is a BApplication hook function that presents a BMessage with one or more entry refs for the app to process. In Rephrase, the appropriate action is to open a new window for each specified ref. In the future, the system will call RefsReceived() when files are dropped onto the Rephrase binary. It made sense to put the file opening code where it will be used. Implementation Details
Next Week: Resizing and Scroll bars
After the Quiet Period
We're now out of the customary 25-day period after the effective date of an IPO -- July 20th in our case -- during which we were embargoed from making public statements. The idea behind the silence is to let the market "digest" the news of an IPO before a company can offer information not contained in its prospectus. The prospectus, edited under the watchful eye of the SEC, contains the data investors use to evaluate the pros and cons of buying stock in a company. The rule is that you're not supposed to add anything to a prospectus during the IPO process for 25 days after the offering is made. The very simple, sensible idea behind this rule is to level the investing field and make sure all investors operate with the same set of data. This makes investors trust the workings of the market and is good for the investing business. Moving from lofty principles to practical consequences, maintaining this atmosphere of good faith creates certain restrictions that every public company operates under. For instance, when discussing the future of our business, in this newsletter or elsewhere, we have to be careful not to impart information that would create an imbalance between individuals who received the data and the public at large. So, in the interest of balance we shouldn't make revenue or earnings projections or issue statements that would lead one to infer such a forecast. More specifically, we can say this new release is terrific because it contains these new features and fixes these embarrassing bugs. We can even say it's better than the Sumo Wrestler OS for digital media over broadband, but we cannot say that it will increase our revenue and earnings by such and such percentage. If the spirit of the moment carries us away and moves us to make such an imprudent statement, we're obliged to immediately put out a press release disclosing the information to the general public, in order to restore a level playing field. Today's story doesn't say how the SEC and others would view repeat or seriously disruptive incidents. In the same vein -- giving investors equal access to information and enough time to process it -- earnings reports are released right after the market closes, giving investors time to sleep on the news. Lastly, a word about a paragraph you might have seen in many press releases, including our recent earnings statement. The paragraph starts like this: "The statements contained in this Press Release may contain 'forward-looking statements.' Actual events or results may differ materially as a result of risks...," etc. The intent is to remind readers of press releases, or audiences listening to speeches, not to mistake some forward-looking statements for actual forecasts. For instance, discussion of future releases may or may not contain forward-looking statements, and companies entertaining such discussions may or may not want to remind readers of the limits and context. Although these rules may sound constraining, they seem less so when we keep in mind who benefits: shareholders and, as a result, the companies they invest in.
1997 Be Newsletters | 1995 & 1996 Be Newsletters Copyright © 1999 by Be, Inc. All rights reserved. Legal information (includes icon usage info). Comments, questions, or confessions about our site? Please write the Webmaster. |