ARABICLOGO
The First
Arabic Programming Language Project
Mustafa
Elsheikh
<elsheikhmh (at) hotmail (dot) com>
Adding Arabic Support to UCBLogo Core
Set font and direction: 1
Maximize Window 2
Create Buffer and Cursor 2
Newline Buffer Reset 2
Set Cursor Action 3
Set Backspace Action 3
Buffered Writing 3
Both fixed-width font, and variable-width fonts work well for Arabic applications. However, fixed font is used here for means of simplicity of character width calculations.
UCBLogo has a font setting mechanism, based on setting logofont environment variable before entering logo. This mechanism is completely disabled in this version. Only fixed font is allowed.
Setting font in ConsoleWindowsFunction() function, which is responsible of handling Windows message WM_CREATE.
[code]
in message WM_CREATE:
// set text alignment to be RTL
SetTextAlign(memConDC, TA_RIGHT^TA_RTLREADING);
SetTextAlign(ConDC, TA_RIGHT^TA_RTLREADING);
// select System Fixed
font, or use CreateFont()
hfont =
GetStockObject(SYSTEM_FIXED_FONT);
SelectObject(memConDC,
hfont);
SelectObject(ConDC, hfont);
[code]
According to MSDN TA_RTLREADING means
[quote]
Middle-Eastern Windows: The text is laid out in right to left reading order, as opposed to the default left to right order. This applies only when the font selected into the device context is either Hebrew or Arabic.
[quote]
Mxied along with TA_RIGHT, SetTextAlign() gives the correct action of RTL printing direction.
For graphics screen, font and direction is adjusted such that logo primitive label could display Arabic correctly.
[code]
in win32_turtle_prep()
HFONT hfont = GetStockObject(SYSTEM_FIXED_FONT);
SelectObject(memGraphDC, hfont);
SelectObject(GraphDC, hfont);
SetTextAlign(memGraphDC, TA_RIGHT^TA_RTLREADING);
SetTextAlign(GraphDC, TA_RIGHT^TA_RTLREADING);
[code]
In order to display Arabic correctly, the window needs to be maximized all the time, so initially, window is maximized. Resizing is not enabled.
[code]
in WinMain()
// show the windows maximized
ShowWindow(hMainWnd, SW_MAXIMIZE);
in ParentWindowFunc()
on message WM_SIZE
if (wParam != SIZE_MINIMIZED)
ShowWindow(hMainWnd, SW_MAXIMIZE);
[code]
Create global buffer string alp_buffer, and cursor alp_cursor. Initialize each.
[code]
in globals.h
extern char *alp_buffer;
extern int alp_cursor;
in win32trm.c
char *alp_buffer;
int alp_cursor;
in init()
// initialize alp_buffer, ensure the empty contents, and reset cursor
alp_buffer = malloc(sizeof(char)*80);
strcpy(alp_buffer, "\0");
alp_cursor = 0;
[code]
On newline, buffer is reset, also cursor.
[code]
in win32_putc()
if (c == '\n') {
// if new line, reset buffer and cursor
strcpy(alp_buffer, "");
alp_cursor = 0;
[code]
Logo primitive setcursor adjust the alp_cursor too.
[code]
in win32_lsetcursor()
// set alp_cursor to x_user_input
alp_cursor = getint(car(arg));
[code]
On backspace, a backspace character is printed. Later in real printing routine, backspace is interpreted properly.
[code]
in update_coords()
else if (ch == '\b') {
// ensure the backspace action
CharOut('\b');
[code]
The whole buffer is reprinted on each character print. That's because Arabic letters are not rendered properly unless they are printed in word-by-word, not character-by-character. The start of line is determined as maxX, maximum characters in page width, minus cursor position. A -5 is added to beautify the start of line. Buffering is done as follows: if the character is not a backspace, append it to the end of the buffer. Otherwise, i.e., a backspace, remove the last letter on buffer. Then print the buffer.
[code]
in CharOut()
int alp_xpos;
// 1 character instead of 3
char nog[1];
if(c == '\b') {
// if backspace, remove the last character in the buffer
alp_buffer[strlen(alp_buffer)-1] = '\0';
} else {
// else, append the character to the end of buffer
strcat(alp_buffer, nog);
}
// anyhow, print the whole buffer starting @ alp_xpos
alp_xpos = maxX - tm.tmAveCharWidth * alp_cursor - 5;
TextOut(memConDC, alp_xpos, ypos, alp_buffer, strlen(alp_buffer));
TextOut(ConDC, alp_xpos, ypos, alp_buffer, strlen(alp_buffer));
[code]