Saturday, August 9, 2008

Quick note on UnicodeString

Jan Goyvaerts has introduced some key information about Unicode in Delphi 2009.
http://www.micro-isv.asia/2008/08/get-ready-for-delphi-2009-and-unicode/

Marco Cantu has made a performance comparison between AnsiString and UnicodeString.
http://blog.marcocantu.com/blog/tiburon_unicode_video_5.html

Conclusion

According to the information, so much I have collected in the past a few months, I summarized them as the following points:
  1. Simple projects can be upgraded to Delphi 2009 without any modifications. Projects with heavy string operations or file operations could be compiled as well. But they should be tested completely before release.
  2. UnicodeString is based on the same concept as AnsiString. So it is very fast and efficient, although it is a little bit slower than AnsiString.
  3. In compare with WideString much less memory will be allocated for UnicodeString. If it is not necessary, you had better switch WideStrings to UnicodeStrings for a performance boost.

UPDATE 1: Here and here are detailed performance tests
 

Tuesday, June 3, 2008

Google features in a shell

Just found an interesting site http://goosh.org/. It is powered by Google APIs.

 

Tuesday, May 27, 2008

Do not give the OK button a keyboard accelerator

Raymond Chen, a well-known developer on the Windows Shell team at Microsoft, mentioned a principle about dialog design in his blog: Do not give the OK button a keyboard accelerator [1].

But it is funny, that even their own products do not follow this principle strictly. A remarkable example is the "Restart Prompt Dialog of Automatic Updates" in WindowsXP. Both buttons "Restart Now" and "Restart Later" have a keyboard accelerator. If this dialog pops up, while I am pressing ALT+N, the current Windows session will be terminated immediately. And there is no Postpone button either. This button appears in Windows Vista, but there is no option "Do not prompt me again, I will restart my computer later.". If I do not intend to restart my computer very soon, I have to press "Postpone" in every 4 hours. It is really annoying! Not only the unfriendly design, but also infinite critical Windows updates. The only one option for me is to turn off "Automatic Updates".

According to the great design principles [2]: I suggest remove those keyboard accelerators and add a 10-second-delay before restarting Windows, so that user can cancel this action. This is called user experience!

References

  1. Gentle reminder: On a dialog box, do not give OK and Cancel accelerators
  2. How to Design a Great User Experience
 

Monday, May 26, 2008

Form disappeared

After I started working on dual monitors, I have found another interesting issue:

  1. Create a new application with a main form and a sub-form.
  2. Set the property Position of the sub-form to poMainFormCenter
  3. Create a button "Show Sub-Form" on main form.
  4. Move more than 50% area of the main form out of the main screen.
  5. Click the button, we created.
The sub-form disappeared! Because the popup position of sub-form is out of the screen. I did a similar test with Internet Explorer. Its dialog will be shown at the corner of the screen. It can be regarded as a bug, so I have reported this issue to QualityCentral [1] as well.

Solution

This time you have to modify Forms.pas
  1. Copy Forms.pas to your project folder,
  2. find and replace with the following code,
  3. and then recompile your project again.

{$IFDEF FIXUP_FORM_POPUP_POSITION}
function GetPrimaryMonitor: TMonitor;
var
I: Integer;
begin
for I := 0 to Screen.MonitorCount - 1 do
begin
Result := Screen.Monitors[I];
if Result.Primary then
Exit;
end;
Result := Screen.Monitors[0];
end;

procedure CenterFormToPrimaryMonitorCenter(var X, Y: Integer;
AForm: TCustomForm);
var
R: TRect;
begin
R := GetPrimaryMonitor.WorkareaRect;
X := R.Left + (R.Right - R.Left - AForm.Width) div 2;
Y := R.Top + (R.Bottom - R.Top - AForm.Height) div 2;
end;

procedure SnapFormToMonitorEdgeOnDemand(var X, Y: Integer;
AForm: TCustomForm);
var
DistanceLeft, DistanceRight: Integer;
CenterMon: TMonitor;
R: TRect;
begin
CenterMon := Screen.MonitorFromPoint(
Point(X + AForm.Width div 2, Screen.DesktopHeight div 2));
R := CenterMon.WorkareaRect;
// Adjust X-pos
DistanceLeft := X - R.Left;
DistanceRight := R.Right - (X + AForm.Width);
if (DistanceLeft < 0) and (DistanceRight < 0) then
begin
if DistanceLeft >= DistanceRight then
X := R.Left // Snap to left edge
else X := R.Right - AForm.Width; // Snap to right edge
end
else if (DistanceLeft < 0) or (DistanceRight < 0) then
begin
if DistanceLeft < 0 then
X := R.Left // Snap to left edge
else X := R.Right - AForm.Width; // Snap to right edge
end;
// Adjust Y-pos
if Y < R.Top then
Y := R.Top
else if Y > R.Bottom - AForm.Height then
Y := R.Bottom - AForm.Height;
end;
{$ENDIF}

procedure TCustomForm.CMShowingChanged(var Message: TMessage);
// ...
if (FPosition = poScreenCenter) or
((FPosition = poMainFormCenter) and (FormStyle = fsMDIChild)) then
begin
if FormStyle = fsMDIChild then
begin
X := (Application.MainForm.ClientWidth - Width) div 2;
Y := (Application.MainForm.ClientHeight - Height) div 2;
end else
begin
{$IFDEF FIXUP_FORM_POPUP_POSITION}
CenterFormToPrimaryMonitorCenter(X, Y, Self);
{$ELSE}
X := (Screen.Width - Width) div 2;
Y := (Screen.Height - Height) div 2;
{$ENDIF}
end;
{$IFDEF FIXUP_FORM_POPUP_POSITION}
SnapFormToMonitorEdgeOnDemand(X, Y, Self);
SetBounds(X, Y, Width, Height);
//SetWindowToMonitor() will cause unexpected popup position change!
{$ELSE}
if X < Screen.DesktopLeft then
X := Screen.DesktopLeft;
if Y < Screen.DesktopTop then
Y := Screen.DesktopTop;
SetBounds(X, Y, Width, Height);
if Visible then SetWindowToMonitor;
{$ENDIF}
end
else if FPosition in [poMainFormCenter, poOwnerFormCenter] then
begin
CenterForm := Application.MainForm;
if (FPosition = poOwnerFormCenter) and (Owner is TCustomForm) then
CenterForm := TCustomForm(Owner);
if Assigned(CenterForm) then
begin
X := ((CenterForm.Width - Width) div 2) + CenterForm.Left;
Y := ((CenterForm.Height - Height) div 2) + CenterForm.Top;
end else
begin
{$IFDEF FIXUP_FORM_POPUP_POSITION}
CenterFormToPrimaryMonitorCenter(X, Y, Self);
{$ELSE}
X := (Screen.Width - Width) div 2;
Y := (Screen.Height - Height) div 2;
{$ENDIF}
end;
{$IFDEF FIXUP_FORM_POPUP_POSITION}
SnapFormToMonitorEdgeOnDemand(X, Y, Self);
SetBounds(X, Y, Width, Height);
//SetWindowToMonitor() will cause unexpected popup position change!
{$ELSE}
if X < Screen.DesktopLeft then
X := Screen.DesktopLeft;
if Y < Screen.DesktopTop then
Y := Screen.DesktopTop;
SetBounds(X, Y, Width, Height);
if Visible then SetWindowToMonitor;
{$ENDIF}
end
else if FPosition = poDesktopCenter then
// ...
end;

Conclusion

This issue is nothing. The motivation of this article [2] is to suggest you figure out the differences among DesktopRect, BoundsRect and WorkAreaRect. They are almost the same on one monitor environment. But they are totally different on dual monitors, especially when TaskBar is not at its default position.

References

  1. Related discuss at QualityCentral.
  2. The Chinese version of this article (on my blog @csdn)
 

Sunday, April 27, 2008

A not cool thing of TCoolBar

There is a demo project "coolstuf" in Delphi folder. It demonstrates how to build your own web browser with Delphi. Unfortunately it shows you how to re-procedure an issue of TCoolBar as well. "Just drag the (third) Links toolbar to top and then to bottom, repeat it for several times, you will see an extra area (roughly 40px) at bottom of TCoolBar." I call this as a "TCoolBar Bands' Position Problem". If you do not get it, please look at the snapshot.


Snapshot (Red rectangle is the extra area)

If you have read other posts in my blog, you might know, that I am very uncomfortable with such UI problems. So I did some investigation: This issue take place, when one or more bands have a fixed size. (TCoolBand.FixedSize is True) I suppose, that the height of this (fixed-size) band was not updated, when TCoolBar's height was changed. Actually, this is not the only one issue of REBAR controls. For instance: No chevron support, no whole dropdown button support, flickering problem, etc. (I will talk about them later in another post)

Solution

I have reported this issue to QualityCentral [1]. Not like other patches I have made, this time, the solution is not clean enough.

You have to:
  1. Copy ComCtrls.pas to your project folder,
  2. find and replace with the following code,
  3. and then recompile your project again.


procedure TCoolBar.CNNotify(var Message: TWMNotify);
//PATCH-BEGIN
var
I, FID: Integer;
RBBI: TReBarBandInfo;
//PATCH-END
begin
if (Message.NMHdr^.code = RBN_HEIGHTCHANGE) then
if IsAutoSized and (ComponentState * [csLoading, csDestroying] = [])
then begin
//PATCH-BEGIN
for I := 0 to Bands.Count - 1 do
if Bands[I].FixedSize then
begin
FillChar(RBBI, SizeOfReBarBandInfo, 0);
RBBI.cbSize := SizeOfReBarBandInfo;
RBBI.fMask := RBBIM_STYLE;
FID := Bands[I].FID;
Perform(RB_GETBANDINFO, FID and IDMask, Integer(@RBBI));
Perform(RB_SETBANDINFO, FID and IDMask, Integer(@RBBI));
end;
//PATCH-END

ReadBands;
BeginUpdate;
try
if AutoSize then AdjustSize;
finally
EndUpdate;
end;
end
else if IsBackgroundDirty then
Invalidate;
end;

Conclusion

As I mentioned before, REBAR controls (TCoolBar, TCoolBand, TToolBar and TToolButton) have not been implemented correctly as they should be. I did some experiments and made couple of patches. This article [2] is only the part one. There will be part two, part three...

To note that some patches must modify interface declaration and implementation both. Unfortunately Delphi cannot re-compile those modified units, when their interface declaration has been changed. The only one solution, so far as I known, is to create a copy of the whole REBAR control set and modify the new set. I will be appreciated, if someone can suggest any better ways.

References

  1. Related discuss at QualityCentral
  2. The Chinese version of this article (on my blog @csdn)
 

Wednesday, April 9, 2008

Why Safari?

Why so many people love Mac OS? Is it really fantastic or just the way to express their /unique/ personality? These years I struggled with myself for buying a Mac or not. As I do not have deep pockets, a simple start can be trying its browser Safari on my windows box...

"A good name is a good start for a product." After couple of days' testing, my word was proved: Just like its name, Safari is "suffering". (If I am wrong, please correct me.)

First of all, there are two good things I mentioned:

  1. The fonts (except Chinese fonts) are perfect, especially the anti-aliasing effect has impacted me deeply. Text on web pages looks more crisper and easier to read. Although I saw one similar tool to increase the anti-aliasing for Windows, but I prefer to the results of Safari.
  2. When I search some text in a Web page, all matches will be highlighted with an extra large size and in a high contrast color, so that you can find your target easily.

All other experiences of Safari are really nightmares:
  1. There is no "New Tab" button on toolbar. Although user can double click on empty area of tab bar, like other browsers. But by default, when there is only one tab opened, tab bar is invisible. Shall I always stick my fingers on keyboard (to press CTRL+T)? Alternatively, user can also open a tab by middle-button clicking on a link. But it is not handy, why so complicated?
  2. The user interface looks material silver. All buttons especially the close tab "X" on each tab are not easy to be identified. By switching tabs I often close a web page by mistake. Even worse is the function "Reopen Last Closed Window" is belt in menu. I get really nervous while switching tabs. One thing to be noted: When multiple Safari instances are running, it might recover the last closed web page of previous instance, not the current.
  3. There is no drop-down button on address bar. When I try to open a frequently visited website, I have to type several chars and then select it from the list. Hui, my fingers will be permanently damaged after using Safari for one month.
  4. The memory usage is huge. Just run Safari will manipulate ca. 40MB memory. After navigating several simple websites, the usage will increase to 100MB-200MB or more. I did the same test in MSIE or FireFox. They use less.

Conclusion

Safari is suffering. Most problems (I regard as) are related to usability. Apple is proud of its design. But at least Safari disappointed me. I did not see too many highlights on it. I will still keep this toy for web page compatibility tests and hope something really exciting in next major release.
 

Thursday, January 24, 2008

Theme updated

The width of the current theme is fixed. I have updated the css and extend the width from 760px to 900px. DO NOT DELETE THE FOLLOWING THREE IMAGES.