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

Set font and direction:

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]


Maximize Window

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 Buffer and Cursor

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]


Newline Buffer Reset

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]


Set Cursor Action

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]


Set Backspace Action

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]


Buffered Writing

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]