Archive for October, 2004

October 31st 2004

PEMDAS

Dangit. I sat here staring at my code for nearly 20 minutes wondering why when “warning.Level” was 5 it wasn’t getting lighter:

g.ForeColor = rgb(255, (10-warning.Level * 20) + 55, _
(10-warning.Level * 20) + 55)

I was thinking… Ok, 10 minus 5 is 5. Times 20 is 100. Add 55 and you get 155. So, I should have rgb(255, 155, 155), which would look like this. But no. I kept getting pure red. Finally, I realized that the order of operations got me tonight. I rarely get stuck by that. I must be tired.

For those who don’t know what’s wrong — the computer, as well as any person who is thinking straight, would evaluate multiplication before subtraction, so it was actually saying: 5 times 20 is 100. 10-100 is -90. Add 55 and you get -35. REALbasic, however, for negative numbers in the function rgb will just set the elements to 0, which explains why I was getting solid red for my two values of warning.Level I was testing.

Bah, I’m going to bed early tonight ;)

No Comments yet »

October 31st 2004

RBScript Exposing Classes

RBScript is very powerful. I’m using it to drive exports and “rules” in my program. Why? Because then I have all those items being plugin objects, and people could add their own if they want. Since RBScript is also compiled, there isn’t hardly any overhead between REALbasic code and RBScript.

The “problem” (more like, blessing) of RBScript is that it’s sandboxed. It has the basic intrinsic functions, such as string and math operations, but it doesn’t expose anything from the framework. This is good, however, because it means that you can expose exactly what you want to, and nothing else. All you do is provide a “Context” object, which lets the user have access to everything on that class.

So, how do you expose more classes than just the context’s class? It’s a little bit of brute work, but it can be done. I’ve devised a pretty cool method to do this which I’m going to share.

The first thing I did was I created a new class that I will have each of my contexts subclass. I called mine “BaseContext” and I decided there needed to be three methods: OwnObject, RetrieveObject, and DisposeObject. Also, I’m using the REALbasic dictionary to help out. Here’s what the class looks like:

Class BaseContext
Private pObjectDict As Dictionary
Protected Function OwnObject(obj As Object) As Integer
Dim v As Variant

If obj = Nil Then Return 0

v = obj

If pObjectDict = Nil Then pObjectDict = New Dictionary

pObjectDict.Value(v.Hash) = v

Return v.Hash
End Function
Protected Sub RemoveObject(hash As Integer)
If hash = 0 Then Return

If pObjectDict = Nil Then pObjectDict = New Dictionary

Try
pObjectDict.Remove hash
Catch k As KeyNotFoundException

End Try
End Sub
Protected Function RetrieveObject(hash As Integer) As Object
If hash = 0 Then Return Nil

If pObjectDict = Nil Then pObjectDict = New Dictionary

Try
Return pObjectDict.Value(hash)
Catch k As KeyNotFoundException
Return Nil
End Try
End Function
End Class

Looks pretty straightforward, right? Well, here’s how we’re going to use it. Insert this into each of the RBScript source files before giving the source to RBScript:

Class RBOwnedClass
Dim privateHash As Integer

Public Sub Constructor( hash As Integer )
privateHash = hash
End Sub

Public Sub Destructor()
pDisposeObject( privateHash )
End Sub
End Class

So, now, whenever there is a Class defined that inherits from RBOwnedClass, it can be constructed with this “hash” when we store in the dictionary. So, how would you use it? Let’s take the Date class for example (note, these aren’t all the methods, and it’s read-only):

Class Date
Inherits RBOwnedClass
Public Function Month() As Integer
Return pDateGetMonth( privateHash )
End Function
Public Function Day() As Integer
Return pDateGetDay( privateHash )
End Function
Public Function Year() As Integer
Return pDateGetYear( privateHash )
End Function
Public Function Hour() As Integer
Return pDateGetHour( privateHash )
End Function
Public Function Minute() As Integer
Return pDateGetMinute( privateHash )
End Function
End Class

Now, in the context object, you are responsible for defining pDateGet*. As an example, this is what pDateGetMonth would look like:

Function pDateGetMonth(hash As Integer) As Integer
Return Date(RetrieveObject(hash)).Month
End Function

It is laborious to expose many classes, but take it in sections and it’s not so bad. Plus, you can reuse a lot if you are going to use RBScript again in the future.

For this project, I have to expose my internal data structures in a read-only mode, and then the script can simply loop over all the data and analyze it, export it, etc. RBScript is cool :)

2 Comments »

October 31st 2004

Late night programming

It’s been a long time since I was motivated to stay up this late programming. Although technically it’s 2 AM, it’s basically 3 AM due to the time change.

Remember to roll your clocks back! I’m hitting the sack ;)

No Comments yet »

October 31st 2004

Be wary of copy and paste

So, this is something I think REALbasic could be nicer about. I was combining the two windows earlier that lead to my previous post about menus and cross-platformness. I had a ListBox on both windows named the same thing, because they essentially did the same thing in different contexts. On the main window, it was a list of the names to select which to use, but on the other window, it was which one are you editing.

Well, when I copied the one from the second window, REALbasic was like, “Oh, you already have one of that name, so I’ll rename it to ListBox1 for you.” That’s fine, except then I thought that I had discovered a weird bug involving PagePanels, ListBoxes, and Composite windows. I couldn’t seem to figure out what was causing it — it wasn’t composite windows, it wasn’t the pagepanel/listbox combination. Finally, I noticed in design mode that the name of the ListBox was “Listbox1″, which prompted me to look in the code browser, which said its original name — but the code in it was for the other page in the PagePanel. Damn, 20 minutes wasted ;)

No hard feelings though. It was my fault for designing my window wrong in the first place ;)

No Comments yet »

October 30th 2004

Temporary Disable Control Locking

Well, I’m taking the PagePanel approach to the problem I stated below. However, my program should be using all the window, so I have controls covering the PagePanel’s navigational menu. Problem? Yeah, kind of. I quickly decided to write a bit of code to help use this. Here’s the new WindowState module:

Module WindowState
Dim mWindowDict As Dictionary

Sub PopLockStates(Extends w As Window)
// This is just in case someone codes stupidly <img src='http://www.nilobject.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' />
If mWindowDict = Nil Then mWindowDict = New Dictionary

Dim positions As Collection
Dim controlDict As Dictionary

If mWindowDict.HasKey(w) Then
positions = mWindowDict.Value(w)
Else
Return
End If

// loop over all the controls
Dim i As Integer
Dim r As RectControl
Dim value As Integer

// pop the dictionary off the top
controlDict = positions.Item(positions.Count)
positions.Remove( positions.Count )

// if we don't have any more positions, go a head and
// release our reference to the window
If positions.Count = 0 Then
mWindowDict.Remove w
End If

For i = 0 To w.ControlCount - 1
// We actually only care about
// rect controls. We're going to
// be simple and use a simple integer
// to store the information.
If w.Control(i) IsA RectControl Then
r = RectControl(w.Control(i))

If controlDict.HasKey(r) Then
value = controlDict.Value(r)

r.LockLeft = (Bitwise.BitAnd( value, 2^0 ) <> 0)
r.LockTop = (Bitwise.BitAnd( value, 2^1 ) <> 0)
r.LockRight = (Bitwise.BitAnd( value, 2^2 ) <> 0)
r.LockBottom = (Bitwise.BitAnd( value, 2^3 ) <> 0)
End If
End If
Next
End Sub
Sub PushLockStates(Extends w As Window)
// Create our dictionary if needed
If mWindowDict = Nil Then mWindowDict = New Dictionary

Dim positions As Collection
Dim controlDict As Dictionary

// If we have used this window already,
// store the information in the existing
// collection.
If mWindowDict.HasKey(w) Then
positions = mWindowDict.Value(w)
Else
positions = New Collection
mWindowDict.Value(w) = positions
End If

// loop over all the controls
Dim i As Integer
Dim r As RectControl
Dim value As Integer

controlDict = New Dictionary

For i = 0 To w.ControlCount - 1
// We actually only care about
// rect controls. We're going to
// be simple and use a simple integer
// to store the information.
If w.Control(i) IsA RectControl Then
r = RectControl(w.Control(i))

value = 0

If r.LockLeft Then value = value + 2^0
If r.LockTop Then value = value + 2^1
If r.LockRight Then value = value + 2^2
If r.LockBottom Then value = value + 2^3

controlDict.Value(r) = value
End If
Next

positions.Add controlDict
End Sub
Sub TurnOffLocking(Extends w As Window)
Dim i As Integer
Dim r As RectControl

For i = 0 To w.ControlCount - 1
If w.Control(i) IsA RectControl Then
r = RectControl(w.Control(i))

r.LockLeft = False
r.LockTop = False
r.LockBottom = False
r.LockRight = False
End If
Next
End Sub
End Module

So, how do you use it? Let’s say you want to resize a window without the controls moving too. This would be a problem, but with this code, you can do this: (note, the App.DoEvents(-1) is necessary in this case, but evil. Use with caution.)

self.PushLockStates
self.TurnOffLocking

self.Height = self.Height - 20
App.DoEvents(-1)

self.PopLockStates

And there you have it. I’m using this because I just made my window 20 pixels larger, but don’t want that 20 pixels to be there at runtime. Now I can navigate my PagePanel easily!

No Comments yet »

October 30th 2004

Cross Platform Woes

I’ve began a project in which I am going to end up shipping on Mac OS X, Windows, and Linux. REALbasic makes this rather easy, since you can lay your application out once and not really have to worry about much else, unless you use advanced features such as declares (which I do).

So, why is this in the “frustrations” category? Well, unless you design a one-window interface, you have to deal with menus. Menus in REALbasic are done in a neat way, but they can’t solve the problems of the fundamental difference between OS X and Windows/Linux. On the Mac, there is always just one menubar. If you have a main window, and another window that supplements the first window, you run into this problem. Where do you put your menus?

You don’t want every window on Linux and Windows to have the full menubar, yet you want certain things to work. On Windows, I would just turn on MDI, but Linux doesn’t have the concept (it’s faked in some applications). In MDI, it behaves much more like the Mac, but you have the other problem that MDI is often despised.

In my program, you should be able to bring up the second window and press Command- (or Control-) S to save the document. So, menu command should be shared. But because of me targetting Linux, I can’t just use MDI and live with it.

So, here’s why this is in the tips category:

One option is to have a complete menu bar on the Mac, and smaller menubars for each window on Windows/Linux. It’s not as bad as it seems. Sure, you have to visually lay out multiple sets of menu bars, but it’s easy to make work at runtime by simply saying “myWindow.MenuBar = new MyMenuBar”. However, this option doesn’t work well for me, since my two windows are very tightly integrated and share too many commands.

The unreleased version of REALbasic is going to be a one-window interface, similar to a tabbed-browser. This is the other way to solve the problem, and one of the reasons we switched to the one-window interface. In current versions, I would recommend if you have a fixed number of windows that you use a mode-switch style integrated with a PagePanel. If you’re in the REALbasic betas program and want to discuss how I would do it in version 6, feel free to contact me. Or, come to REAL World, as there will most likely be a feature there about it.

Since I am using REALbasic 5.5 for the development, I can’t use that feature, so I will most likely be using a PagePanel.

Well, this is getting to be rather long, and I wrote it mainly to formulate thoughts of how to approach my program ;)

On the plus side, I do plan on opening up the development of this program as soon as I think of a good name and implement a couple of features more. Not open source due to me being greedy and wanting to earn a few bucks for a down payment on a house. By open, I mean public beta demos, plenty of entries about things that I’ve done and encountered.

No Comments yet »

October 30th 2004


No Comments yet »

October 21st 2004

Why does the bug happen?

So, here’s an interesting story. Yesterday a bug was confirmed that only happened on Linux, but worked fine on OS X, Windows, and OS 9. Ok, good, right? So, we let the people who reported it know that it was a bug.

Then, they ask, “Why does it happen on Linux but not the other platforms?” Well, the obvious answer is, it’s a different operating system that requires slightly different code. But I guess it’s not that obvious. However, the funny thing is one of us came up with this:

“We forgot to implement that particular bug on the other platforms.”

We didn’t send it of course, but it’s still funny.

No Comments yet »

October 21st 2004


No Comments yet »

October 6th 2004

REALbasic Syntax Highlighter

I’ve released my REALbasic Syntax Highlighter at http://realbasic.maccoding.com/phprbsyntax/. The REALbasic Gazette has started making use of it, and I hope others follow suit! I do plan on releasing the source to my b2evolution plugin, as well as a WordPress plugin, but both will come when I have more time to clean up those files.

So, just for fun, here’s another example piece of RB code:

Private Sub Execute(item As String, args() As String)
#If TargetMachO Or TargetLinux
#If TargetMachO
Const libc = "/usr/lib/libc.dylib"
#Else
Const libc = "libc.so.5"
#EndIf

Declare Function fork Lib libc As Integer
Declare Function execvp Lib libc (path As CString, _
args As Ptr) As Integer
Declare Sub _exit Lib libc (returnCode As Integer)

Dim pid As Integer
Dim argsBlock As MemoryBlock
Dim argsCstrings(-1) As MemoryBlock
Dim i,c As Integer
Dim err As Integer

args.insert 0, item
c = ubound(args)
argsBlock = New MemoryBlock((c+2)*4)
For i = 0 To c
argsCstrings.Append args(i) + chr(0)
argsBlock.ptr(i*4) = argsCstrings(i)
Next

pid = fork

If pid = -1 Then
msgBox "Error forking."
ElseIf pid = 0 Then
//child
err = execvp(item,argsBlock)
_exit 0
End If
#EndIf
End Sub

That function will launch an executable by path (must be POSIX), and pass in arguments to the application.

No Comments yet »

Next »

  • Current Status

    • Life: Jonathan tweeted Another order from @zappos upgraded. All my orders have been upgraded to overnight... lucky, or is this standard? (Updated 15 hours, 16 minutes ago)
  • Pages

  • Meta