Archive for the 'Tips' Category

May 21st 2007

Example Code from REAL World: List of available encodings

This is the example code from my REAL World presentation on declares. As I did last year, I asked for a declare someone in the audience was wanting to have written, and did it on the spot to show how to go from finding the docs to having working code. This year, someone needed to find a list of available encodings. This code only works on the Mac currently.

Function AvailableEncodings() As TextEncoding()
Dim out() As TextEncoding

#If TargetCarbon
Declare Function CFStringGetListOfAvailableEncodings Lib "CoreFoundation" As Ptr
Const kCFStringEncodingInvalidId = &hffffffff

Dim list As Ptr = CFStringGetListOfAvailableEncodings
Dim i As Integer
While list.Int32(i * 4) <> kCFStringEncodingInvalidId
out.Append Encodings.GetFromCode( list.Int32( i * 4 ) )
i = i + 1
Wend
#EndIf

Return out
End Function

Enjoy!

1 Comment »

April 29th 2007

Todoist+Quicksilver=Productive Organization

First, let me get to the nitty gritty for those who are here for the plugin and not my experiences. Today I’m pleased to announce that in a joint effort with Todoist.com, a Quicksilver module is available for download.

Why in the world would I care?

It may very well be that you don’t care, and perhaps you shouldn’t. Perhaps you’re the type of person who never has any problems remembering to do something. However, if you’re like me, keeping organized and remembering what needs to get done and when both at home, the office, or wherever is always a battle.

A couple years ago, I read the book Getting Things Done: The Art of Stress-Free Productivity, and I immediately “got it.” But I didn’t have a mechanism to organize things that I could stick with.

I began writing my own application, using others, etc., but recently I stumbled upon Todoist which solves the problem in a very simple and elegant way. It’s not exactly a purist implementation of the GTD philosophy, but it is easy to use and powerful enough for my needs.

But I still couldn’t get used to it — it required a visit to the site, clicking on the project I wanted to add the item to, and then adding it. It should be simpler.

Enter Quicksilver. I tried using Quicksilver a year or two ago, but it never quite caught on with me. After recently encountering QuickSilver - A Better OS X In Just 10 Minutes I downloaded it again and began using it in my regular workflow. Putting two and two together, I knew I should write a Quicksilver module for Todoist.

I emailed the developer, and heard back very quickly. With him designing an API, I wrote up a module this weekend. I’m proud to show it off here. It’s pretty simple to use. Edit: There is now a Quicksilver integration guide on the Info page in Todoist.

The usage is pretty straightforward if you’re a seasoned Quicksilver user. If you’re just beginning, bring up Quicksilver’s window using the keyboard shortcut assigned in the preferences. Type a period (”.”). This switches Quicksilver into text entry mode instead of searching mode. Type in the item you want to add to Todoist. When you’re done, press Tab.

Now, find “Add Todoist item to…”. This usually can be done by simply typing “add”. Once selected, press Tab again.

Lastly, either type in the name of the project you want to add this item to or simply use the arrow keys to navigate the list. When complete, press Return. You’ve just added an item to Todoist.

For me, this is the last key in my puzzle for searching for an easy way to remain productive, but still be able to quickly note things as they come up.

Not working right or want something added?

This plugin is a work in progress, mainly with the graphical aspects. Not being a designer myself, I’m doing the best I can. Any bugs or feature requests for this module should be sent to me and not to the fine folks at Todoist.

Good luck, and happy lifehacking.

Since posting this, a few bug fixes have been made. The current version for download is “A0″. If you have an earlier version, please download the latest version.

27 Comments »

March 15th 2007

Syntax Highlighting in the Feedback System

Did you know that you can put [code]Dim foo as Integer[/code] tags into the feedback system to get a report to syntax highlight?

Comments Off

March 12th 2007

Shorter feedback URLs

Ever wished there were a shorter feedback URL? Or, did someone mention a bug ID without the full URL? No fears, just simply type support.realsoftware.com/feedback/<BUG_ID>. It will automatically expand to the full URL.

2 Comments »

March 1st 2007

How to write a “Pause”

While I don’t think Pause would make a good addition to the language, there are situations I know that it’s useful. However, if you’re not writing a threaded application, it isn’t obvious how to do it except for something like this:

Sub Pause( seconds As Double )
Dim target As Integer = Ticks + seconds * 60
While target > Ticks()
Wend
End Sub

There are cons to this approach: it eats up CPU cycles, and it’s horribly inefficient. It’s much easier to write:

Sub Pause( seconds As Double )
App.SleepCurrentThread( seconds * 1000 )
End Sub

Voila, one line of code that sleeps your app to the system, or lets other threads run in the background. Simple and elegant.

Comments Off

October 17th 2006

bool vs Boolean

This mostly affects plugin authors, but it also does affect any REALbasic users that are writing declares that have structures containing the “bool” datatype.

For plugin authors, you must be careful of what you put in the structure you use to represent your control or class’s data. The sizeof( yourStructure ) must be the same on all platforms because the IDE can only gather information about the one the IDE is able to load. For example, if the sizeof( yourStructure ) on Windows is 72, and on the Mac, it is 86, there will be problems when building on Windows for the Mac because the IDE will tell the compiler that your object is only 72 bytes large, and on the Mac it will promptly overwrite that buffer.

How does this size-mismatch happen? The most common cause is definitely the use of the C-Preprocessor inside of the structure declaration. This is common because on the Mac your control may have an HIViewRef while on Windows it will be an HWND, or you may need extra data on Linux to represent your control. There are two good solutions to this. The first is a little more fragile, which is to simply add padding by adding dummy variables to your structure where needed. The second is the preferred method if you’re writing a C++ plugin: make the structure only contain a pointer to a C++ class that you create in the class/object’s constructor. This allows you to easily use the bridge pattern as well to separate platform-specific logic.

The other cause is less common but harder to debug: Let’s examine this structure:

struct {
  bool mEnabled;
  REALstring mTitle;
};

Now, this structure is the same on Windows, Linux, Classic PEF, Carbon PEF, and Carbon Mach-O i386. However, on Carbon Mach-O PowerPC, the bool datatype is 4 bytes long, as opposed to 1 byte. In this situation, I urge you to use the Boolean datatype. It’s a built-in typedef on the Mac, and the SDK defines it for Windows and Linux. It will be the same on all platforms, which will alleviate these problems.

These small issues may not sound like a huge deal, but buffer overruns can yield endless weird issues, the most obvious being crashes.

Comments Off

April 10th 2006

Type-Select Listbox

I wrote this class a year ago at home in hopes of adding it to the REALbasic IDE, then forgot about it until this morning. Have you ever wanted a listbox in your program to support Type-selection like in the Finder or Windows Explorer? Well, just use this class. It behaves the way each platform should, and does it in an efficient manner.

Class TypeSelectListbox
Inherits Listbox
// Constants
Private Const TypeSelectTimeout = 30

// Properties
Private Dim mLastTypeTime As Integer
Private Dim mTypeBuffer As String
Private Dim mCachedRows() As String
Private Dim mCachedRowIndices() As Integer
Private Dim mDidEncounterNonRepeatedChar As Boolean
Dim TypeSelectColumn As Integer

// New events
Event KeyDown(key As String) As Boolean

// Event implementations
Function KeyDown(key As String) As Boolean Handles Event
// We want to call through to the next implementation of the KeyDown event, so that they can handle
// the key first. We're sort of the last-resort.
If Not KeyDown(key) Then
If asc(Key) > 31 And asc(key) < 127 And Not (Keyboard.OptionKey Or Keyboard.AltKey Or _
Keyboard.ControlKey Or Keyboard.CommandKey) Then

// It's ascii, we should try to do a typeahead
If mLastTypeTime + TypeSelectTimeout > Ticks Then
mTypeBuffer = mTypeBuffer + key
mLastTypeTime = Ticks
Else
mTypeBuffer = key
mLastTypeTime = Ticks
Redim mCachedRows(-1)
Redim mCachedRowIndices(-1)
mDidEncounterNonRepeatedChar = False
End If
Dim slen As Integer = Len( mTypeBuffer )

#If TargetWin32 Or TargetLinux
// On Windows and Linux, we must check to see if the first row has the same letter as the
// key. If so, we will cycle to the next row with the same key combination. Else
// we will find the first row that contains the typeahead.
Dim found As Boolean
If me.ListIndex >= 0 And Left( me.Cell( me.ListIndex, TypeSelectColumn ), 1 ) = Key And Not mDidEncounterNonRepeatedChar Then
// Start at the current selection, and move forward. If we can't find another one starting with this
// key, go back to the start, and try again.
For i As Integer = me.ListIndex + 1 To me.ListCount - 1
If Left( me.Cell( i, TypeSelectColumn ), 1 ) = key Then
me.ListIndex = i
found = True
Exit
End If
Next
If Not found Then
For i As Integer = 0 To me.ListIndex
If Left( me.Cell( i, TypeSelectColumn ), 1 ) = key Then
me.ListIndex = i
found = True
Exit
End If
Next
End If
Return True
Else
mDidEncounterNonRepeatedChar = True
// Loop over the rows finding the first instance of mTypeBuffer
For i As Integer = 0 To me.ListCount - 1
If Left( me.Cell( i, TypeSelectColumn ), slen ) = mTypeBuffer Then
me.ListIndex = i
found = True
Exit
End If
Next
End If
If Not found Then beep
Return True
#Else
// On the Mac, the behavior is different. We will always need a complete list of items in
// the listbox. We will always find the first instance of an item that has this prefix.
// First, check to see if we have the correct number of rows still.
If ubound(mCachedRows) <> me.ListCount - 1 Then
// Fill up the array
For i As Integer = 0 To me.ListCount - 1
// Do an insertion sort. I switched to a binary lookup mechanism because
// doing an insertion sort on this list because when we had more than 1,000 rows
// the delay was obvious. However, with this code, it's not even noticable when
// using 18,000 rows.
Dim cell As String = me.Cell(i, TypeSelectColumn)
Dim didInsert As Boolean
Dim l,h As Integer
Dim j As Integer
l = 0
h = ubound(mCachedRows)
j = h \ 2
While l <= h
If cell < mCachedRows(j) Then
// It's less than this one, we can set the ceiling
h = j - 1
ElseIf cell > mCachedRows(j) Then
// It's bigger than this one, we can set this as the floor
l = j + 1
Else
// Equal! Yippe!
Exit
End If
j = (h - l) \ 2 + l
Wend

mCachedRows.Insert j, cell
mCachedRowIndices.Insert j,i
Next
End If

// Now, do a binary search for something that starts with mTypeBuffer.
For i As Integer = 0 To ubound(mCachedRows)
If Left( mCachedRows(i), slen ) = mTypeBuffer Then
// This is it.
me.ListIndex = mCachedRowIndices(i)
Exit
ElseIf Left( mCachedRows(i), slen ) > mTypeBuffer Then
// This is the next one... if we couldn't find an exact one before this,
// then we need to select this one
me.ListIndex = mCachedRowIndices(i)
Exit
End If
Next
#EndIf

Return True
End If
End If

// If we didn't handle it, we need to reset these variables.
mDidEncounterNonRepeatedChar = False
mTypeBuffer = key
mLastTypeTime = Ticks
Redim mCachedRows(-1)
Redim mCachedRowIndices(-1)
End Function
End Class


Download this project

Enjoy!

6 Comments »

April 10th 2006

Finding a project item in 2006

One interesting feature users may not know about REALbasic 2005/2006 is that when you open an item for the first time, it will be selected in the project list for you.

I’ve been doing this without noticing, but when I want to select an item that is buried deep in folders, I simply type in the location field the project item’s name, then press return. I then switch back to the project list and change its super/interfaces there.

It’s a bit hidden, but can save a few minutes of locating an item, or having to sort through search results.

2 Comments »

September 24th 2005

Memory BinaryStreams

One cool feature in REALbasic 2005 is the ability to create a binary stream that points to a MemoryBlock. Aaron highlights it in this post on his blog. A quick rehash is that you can do something like this:

Dim bs As New BinaryStream( New MemoryBlock( 0 ) )

Which is a convenient way to construct a “file” in memory. However, what about reading? Well, since 5.5 (IIRC) REALbasic has allowed an automatic conversion from String to MemoryBlock. This can be used to our advantage in this situation. Let’s say I want to read a string as a BinaryStream?

Dim bs As New BinaryStream( myString )

This is extremely convenient. I’ve been using it all morning. This works because the BinaryStream constructor takes a MemoryBlock, and we also allow conversions from String to MemoryBlock.

Finally, you might ask yourself, what happens if I write to that stream? Well, it writes to it — however, it doesn’t write to the string itself. The key word above is “conversion” — the binary stream doesn’t point directly at the string, but to a MemoryBlock containing the data. So, this is 100% safe, and very very convenient.

No Comments yet »

September 13th 2005

REALbasic 2005r3: Continue Statement

REALbasic 2005r3 was released a few minutes ago, and with it comes a Linux release, a lot of bug fixes, as well as a few new cool features. One thing I enjoyed implementing and immediately using was the Continue statement, as well as extended Exit statement syntax. Partially taken from Visual Basic, we now allow:

Exit // exit whatever loop we're in
Exit Do // exit the do loop we're inside, even if
// we're inside of another loop
Exit For // exit the for loop we're inside, even if
// we're inside of another loop
Exit While // exit the while loop we're inside, even if
// we're inside of another loop

Which is all fine and cool, but then we added an interesting twist tot he “exit for” statement:

Dim map(255,255) As Integer
Dim x, y As Integer

&#8230;

For y = 0 To 255
For x = 0 To 255
If map(x,y) = whatImLookingFor Then
Exit For y
End If
Next
Next

You can now identify which for loop you want to exit by specifying the loop variable. In this case, “y” identifies the outer for loop, and so this exit statement will exit that loop.

The Continue statement is another statement that can be used in a loop to immediately jump to the beginning of the loop, and continue executing. For example:

For i As Integer = 0 To 100
If i = 2 Or i = 31 Then
Continue
End If

// Do something with i
Next

This code will reach the “do something with i” portion in every case except for when i is 2 or i is 31. Often the uses for continue vary, but the prime reason for including it is to help decomplexify* code. For example:

Dim goodDate As New Date
Dim foundIdealDate As Boolean

While Not foundIdealDate
If goodDate.Hour > 20 Or _
(dateGettingPlanned IsA FriendlyDinner And goodDate.DayOfWeek = 6) Then
// We don't like planning things past 8 PM, and
// Fridays can't be for friendly dinners
goodDate.DayOfWeek = goodDate.DayOfWeek + 1
goodDate.Hour = 8
Continue
End If

For Each otherDate As Date In AlreadyPlannedDates
// For simplicity, all dates are exactly 1 hour
If otherDate.TotalSeconds < = goodDate.TotalSeconds And _
otherDate.TotalSeconds + 60*60*60 > goodDate.TotalSeconds Then
// In this case, we know we overlap with this date, so we might
// as well set the idealDate to the hour after this
goodDate.TotalSeconds = otherDate.TotalSeconds + 60*60*60
// We don't need to evaluate anymore, we conflicted &#8212; just continue
Continue While
End If
Next

// Check a few more things, and finally
foundIdealDate = True
Wend

In this example, we have several points where we hand-calculate the best “next” spot to check. Instead of having a lot of nexted if statements, a few temporary variables, or the dreaded GoTo statement**, we can simply use the new continue statement, and we’ll jump back to the top of the loop, and continue with execution again.

*While on the phone with Mars the other day, he used “my” word, complexify. I was pleased that it’s catching on, although I don’t actually know if he heard it first from me or not.
**GoTo can be used well in certain cases, but every time you’re about to use it, you should consider if there’s a better way :)

Have fun with r3. Time for me to get to work on r4!

No Comments yet »

Next »

  • Current Status

    • Life: Jonathan tweeted Is Microsoft more environmentally friendly because Windows Recycles while OS X throws things away? (Updated 10 hours, 1 minutes ago)
  • Pages

  • Meta