Hello, everyone!

For the past two weeks I have been working on a pair of libraries, textioc.h and guilibce.h, for the TI-84 Plus CE. textioc provides some useful functions such as alpha/numerical input and printing auto-wrapped text. guilibce is a loose collection of functions for drawing GUI elements such as containers, buttons, and scroll bars.

This is the current list of functions for textioc:

Code:
void textio_PrintWrappedText(char text[], uint24_t width, uint8_t xPos, uint8_t yPos);

/* maxWidth is in pixels */
void textio_PrintTruncatedStringXY(char string[], uint24_t max_width, uint24_t xPos, uint8_t yPos);


uint24_t textio_NumericalInput(uint8_t xPos, uint8_t yPos, uint8_t magnitude_limit);
char *textio_LetterInput(uint24_t xPos, uint8_t yPos, size_t buffer_size);


And this the list of functions I have so far for guilibce:

Code:
/* GUI Element Config Functions
// ----------------------------------
void gui_SetTitledContainerConfig(outlineColor, bodyColor, bannerColor, titleColor [,shadowColor]);
void gui_SetContainerConfig(outlineColor, bodyColor, [,shadowColor]);
void gui_SetMenuConfig(outlineColor, bodyColor, selectionColor, itemFGColor, subMenuArrowSprite, [,shadowColor]);
void gui_SetBalloonContainerConfig(outlineColor, bodyColor, [,shadowColor]);
void gui_SetRadioButtonConfig(onStateSprite, offStateSprite, labelFGColor, labelBGColor);
void gui_SetCheckBoxConfig(onStateSprite, offStateSprite, labelFGColor, labelBGColor);

// Possible implementations:
void gui_SetScrollBarConfig(scrollButtonSprite);
void gui_SetRadioButtonLockedConfig(onStateSprite, offStateSprite, labelFGColor, labelBGColor);
void gui_SetCheckBoxLockedConfig(onStateSprite, offStateSprite, labelFGColor, labelBGColor);

*/

/* GUI Element Functions
// -----------------------------
void gui_TitledContainerFullScreen(title);
void gui_TitledContainer(xPos, yPos, width, height);
void gui_Container(xPos, yPos, width, height);

// item#Type: 1 = normal; 2 = subMenu; 3 = dividerAbove; 4 = subMenuAndDividerAbove
void gui_Menu(xPos, yPos, item1, item1Type, ...);

// arrowDirection: 1 = up; 2 = down; 3 = left; 4 = right
void gui_BalloonContainer(xPos, yPos, width, height, arrowDirection);

void gui_RadioButton(xPos, yPos, label, state);
void gui_CheckBox(xPos, yPos, label, state);

// Possible implementations:
void gui_ScrollBarHorizontal(xPos, yPos, height, initialPos, startPos, rangePos);
void gui_ScrollBarVertical(xPos, yPos, width, initialPos, startPos, rangePos);
void gui_RadioButtonLocked(xPos, yPos, label, state);
void gui_CheckBoxLocked(xPos, yPos, label, state);


// Advanced GUI Element Functions
// -------------------------------------------
void gui_BalloonContainerAutoAdj(xPos, yPos, width, height, arrowDirection);


I am currently working out the underlying design of guilibce, deciding how the elements will work, how they can be modified, whether there will be a GUI stack like DCSLibs, and so on. My goal is to make guilibce as flexible and intutive as possible.

Both the text-wrapping function and the PrintTruncatedStringXY function in textio have been implemented and debugged. This weekend, I have almost completed the LetterInput function which allows the user to enter uppercase and lowercase letters. By changing the function slightly, I believe I can easily create a function that will take only numbers and another function that will take both numbers and letters.

However, while I was working on the last part of the LetterInput function I found that I hadn't freed the pointer to the buffer that holds the user input, creating a potential memory leak. Below is the code for the function with the proper calls to free() but which does not return the user input.

Code:
char* textio_LetterInput(uint24_t xPos, uint8_t yPos, size_t buffer_size) {
   
   char *buffer_ptr;                  // Buffer for user input
   char *letter_ptr;                  // Holds current char
   bool caps_on = true;
   uint8_t text_BG_color;
   uint8_t text_FG_color = 0x00;
   uint24_t cursor_xPos = xPos + 1;
   uint24_t i;                        // Counter variable
   bool cursor_active = false;
   uint8_t key = '\0';
   const char *lowercase_letters  = "\0\0\0\0\0\0\0\0\0\0\0wrmh\0\0\0\0vqlg\0\0\0zupkfc\0\0ytojeb\0\0xsnida\0\0\0\0\0\0\0\0";
   const char *uppercase_letters  = "\0\0\0\0\0\0\0\0\0\0\0WRMH\0\0\0\0VQLG\0\0\0ZUPKFC\0\0YTOJEB\0\0XSNIDA\0\0\0\0\0\0\0\0";
   
   // Debugging variables
   uint8_t j;
   char *pLetter;
   
   buffer_ptr = malloc(buffer_size + 1);
   if (!buffer_ptr)
      return NULL;
   memset(buffer_ptr, '\0', buffer_size + 1);
   
   letter_ptr = buffer_ptr;
   
   gfx_SetTextScale(1,1);
   gfx_SetTextFGColor(text_FG_color);
   
   for (;;) {
      
      gfx_SetTextXY(xPos, yPos);
      gfx_PrintString(buffer_ptr);
      
      cursor_active = false;
      if (letter_ptr < buffer_ptr + buffer_size)
         cursor_active = true;

      dbg_sprintf(dbgout, "cursor_active = %d\n", cursor_active);
      
      cursor_xPos = xPos + 1;
      if (letter_ptr > buffer_ptr)
         cursor_xPos += gfx_GetStringWidth(buffer_ptr);
      
      
      text_BG_color = gfx_GetPixel(cursor_xPos, yPos);
      gfx_SetTextBGColor(text_BG_color);
      gfx_SetTextTransparentColor(text_BG_color);
      
      // Debugging
      dbg_sprintf(dbgout, "letter_ptr = %x\nbuffer_ptr = %x\n", letter_ptr, buffer_ptr);
      
      dbg_sprintf(dbgout, "buffer =");
   
      pLetter = buffer_ptr;
      for (j = 0; j < buffer_size; j++)
         dbg_sprintf(dbgout, "  %x", *pLetter++);
      
      dbg_sprintf(dbgout, "\t|");
      
      pLetter = buffer_ptr;
      for (j = 0; j < buffer_size; j++)
         dbg_sprintf(dbgout," %c ", *pLetter++);
      
      dbg_sprintf(dbgout, "|\n");
      
   
   
      // Wait for input and display cursor
      do {
      
         if (cursor_active) {
            gfx_SetColor(0x00);
            gfx_Line(cursor_xPos, yPos - 1, cursor_xPos, yPos + 8);
         };
      
         i = 0;
      
         do {
            key = os_GetCSC();
            i++;
         } while (!key && i < 6000);
      
         if (cursor_active) {
            gfx_SetColor(text_BG_color);
            gfx_Line(cursor_xPos, yPos - 1, cursor_xPos, yPos + 8);         
         };
      
         while (!key && i < 12000) {
            key = os_GetCSC();
            i++;
         };
      } while (!key);
   
      if (key == sk_Clear && letter_ptr == buffer_ptr)
         return NULL;
      
      if (key == sk_Enter) {
         
         
         // Debugging
         dbg_sprintf(dbgout, "buffer =");
   
         pLetter = buffer_ptr;
         for (j = 0; j < buffer_size; j++)
            dbg_sprintf(dbgout, "  %x", *pLetter++);
      
         dbg_sprintf(dbgout, "\t|");
      
         pLetter = buffer_ptr;
         for (j = 0; j < buffer_size; j++)
            dbg_sprintf(dbgout," %c ", *pLetter++);
      
         dbg_sprintf(dbgout, "|\n");
         
         
         // Return only the chars entered and remove
         // all trailing null chars
         
         if (letter_ptr > buffer_ptr) {
            
            // string should contain the final string input plus the null terminator
            free(buffer_ptr);
            return string;
         };
         
         dbg_sprintf(dbgout,"letter_ptr is equal to buffer_ptr");
                        free(buffer_ptr);
         return NULL;
      };
      
      if (key == sk_Clear) {
         while (letter_ptr > buffer_ptr)
            *--letter_ptr = '\0';
         
         gfx_SetColor(text_BG_color);
         gfx_FillRectangle(xPos, yPos, cursor_xPos, 8);
      };
      
      if ((key == sk_Del) && letter_ptr > buffer_ptr) {
         
         letter_ptr--;
         
         // Debugging
         dbg_sprintf(dbgout, "*letter_ptr = %c\n&letter_ptr = %x\n", *letter_ptr, &letter_ptr);
         dbg_sprintf(dbgout, "Deleted char\n");
         
         // Erase char
         gfx_SetColor(text_BG_color);
         gfx_FillRectangle(cursor_xPos - gfx_GetCharWidth(*letter_ptr) - 1, yPos, gfx_GetCharWidth(*letter_ptr), 8);
         
         *letter_ptr = '\0';
      } else {
         // Debugging
         dbg_sprintf(dbgout, "Cannot delete char\n");
      };
      
      if (key == sk_Alpha) {
         gfx_SetTextBGColor(0x00);
         gfx_SetTextFGColor(0xFF);
         gfx_SetTextTransparentColor(0x00);
         gfx_SetColor(0x00);
         
         if (caps_on) {
            caps_on = false;
            gfx_FillRectangle(cursor_xPos, yPos - 1, 9, 10);
            gfx_PrintStringXY("a", cursor_xPos + 1, yPos);
         } else {
            caps_on = true;
            gfx_FillRectangle(cursor_xPos, yPos - 1, 9, 10);
            gfx_PrintStringXY("A", cursor_xPos + 1, yPos + 1);
         };
         
         delay(400);
         gfx_SetColor(text_BG_color);
         gfx_FillRectangle(cursor_xPos, yPos - 1, 9, 10);
         gfx_SetTextFGColor(text_FG_color);
      };
      
      if (cursor_active && (uppercase_letters[key] || lowercase_letters[key])) {
         
         if (caps_on) {
            *letter_ptr = uppercase_letters[key];
            dbg_sprintf(dbgout, "Added uppercase char\n");
         } else {
            *letter_ptr = lowercase_letters[key];
            dbg_sprintf(dbgout, "Added lowercase char\n");
         };
         
         // Debugging
         dbg_sprintf(dbgout, "*letter_ptr = %c\n&letter_ptr = %x\n", *letter_ptr, &letter_ptr);
         
         letter_ptr++;
      } else {
         // Debugging
         dbg_sprintf(dbgout, "No char added\n");
      };
      
      delay(100);
   };
}


My first solution was to allocate memory for another pointer that was exactly as long as the string, copy only the string characters from buffer_ptr, and return that pointer. However, I think this can also cause a memory leak unless the programmer does the following:

Code:
char* user_input;
user_input = textio_LetterInput(50, 50, 10);
/* Do something with user_input... */
free(user_input);


However, I would like the function to be self-contained and not require the programmer to do any extra memory freeing.

Any help would be very much appreciated! Smile
Have the user supply the buffer and buffer length like literally every other standard C function.
Thank you, Mateo!

I thought I had tried everything to get around the leak, but I never thought of that. Now all the rest will be easy!
Progress Update

Following Mateo's advice on user-supplied buffers, I have finished a prototype of the textio_LetterInput function.

This function gets string input from the user in both uppercase and lowercase as well as supporting backspacing, character insertion/deletion, and clearing. The [alpha] key switches between the uppercase and lowercase letters and briefly displays an indicator showing the current case. The [del] key acts as a backspace, and the [clear] key deletes all letters behind the cursor. If there are no letters behind the cursor, pressing [clear] will erase any letters in front of the cursor. Pressing [clear] with no letters behind or in front of the cursor exits the function. The function also exits when the user presses [enter], storing the input in the supplied buffer.

After learning how to use Git and Github from commandblockguy's excellent tutorial, I have pushed the latest version of textioc to Github. The function contains a large amount of debugging code which shows how the function manipulates the input buffer in CEmu.

Here is a demonstration of how the function works:


This demo uses the following code:

Code:
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <tice.h>

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <keypadc.h>
#include <graphx.h>
#include <debug.h>

#include "textioc.h"

void dialog( uint24_t xPos, uint8_t yPos, uint24_t width, uint8_t height, uint8_t banner_color, const char *title);

void main(void) {
   
   char *user_input;
   const char *pass = "PASSWORD";
   const char *message = "Welcome";
   
   user_input = malloc(9);
   memset(user_input, '\0', 9);
   
   gfx_Begin();
   
   // Draw dialogs
   dialog(50, 80, 220, 80, 30, "Access Requested" );
   
   gfx_PrintStringXY("Please enter your password:", 55, 115);
   gfx_SetColor(0);
   gfx_Rectangle(55, 130, 150, 13);
   
   // Get input
   textio_LetterInput(user_input, 20, 58, 132);
   
   if (strcmp(user_input, pass) == 0) {
      gfx_FillScreen(30);
      gfx_SetTextScale(3, 3);
      gfx_SetTextBGColor(30);
      gfx_SetTextFGColor(255);
      gfx_SetTextTransparentColor(30);
      gfx_PrintStringXY(message, 160 - gfx_GetStringWidth(message) / 2, 80);
   };
   
   while (!os_GetCSC());
   
   free(user_input);
   
   gfx_End();
   
}

void dialog( uint24_t xPos, uint8_t yPos, uint24_t width, uint8_t height, uint8_t banner_color, const char *title) {
   
   gfx_SetColor(181);
   gfx_FillRectangle(xPos + 1, yPos + 1, width, height);
   gfx_SetColor(0);
   gfx_FillRectangle(xPos, yPos, width, height);
   gfx_SetColor(banner_color);
   gfx_FillRectangle(xPos + 1, yPos + 1, width - 2, 15);
   gfx_SetColor(255);
   gfx_FillRectangle(xPos + 1, yPos + 17, width - 2, height - 18);
   gfx_PrintStringXY(title, xPos + 4, yPos + 4);
   
}


I would greatly appreciate any recommendations for improving the function in order to make as fast and efficient as possible. Once this function is complete, I can then modify it to create other input functions, such as numerical input, alpha-numerical input, and other specialized functions.
Progress Update

I discovered this morning that I had improperly implemented the textio_PrintWrappedText function and found a few, subtle bugs in the function that produced some odd effects. I fixed the function this evening and added another check to it that makes the function exit when it has reached the bottom of the screen.

A screenshot of the function, using an excerpt from Stevenson’s Treasure Island (the red line shows the right margin):


The code for the screenshot:

Code:
 #include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <tice.h>

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <keypadc.h>
#include <graphx.h>
#include <debug.h>

#include "textioc.h"

void main(void) {
   
   gfx_Begin();
   
   /* void textio_PrintWrappedText(char *text, uint24_t width, uint24_t xPos, uint8_t yPos) */

   textio_PrintWrappedText("Squire Trelawney, Doctor Livesey, and the rest of these gentlemen having asked me to write down the whole particulars about Treasure Island, from the beginning to the end, keeping nothing back but the bearings of the island, and that only because there is still treasure not yet lifted, I take up my pen in the year of grace 17-, and go back to the time when my father kept the \"Admiral Benbow\" Inn, and the brown old seaman, with the saber cut, first took up his lodging under our roof.", 300, 1, 1);
   
   while (!os_GetCSC());   
   gfx_End();
}


I have also added a function called textio_SetInputConfig that customizes the foreground color and the cursor color of the text input function. The updated version of textioc 0.1.00 is available here.

I would greatly appreciate any recommendations for improving textioc. Smile
Many thanks to Jeffitus and beckadamtheinventor for their support and encouragement for textioc!

@beckadam, Thank you so much for your time and effort rewriting textioc in assembly! I really like the new features you’ve added to it! I know very little about ASM, but I hope to learn it quickly in order to help rewrite the library. Very Happy
Captain Calc wrote:
Many thanks to Jeffitus and beckadamtheinventor for their support and encouragement for textioc!

@beckadam, Thank you so much for your time and effort rewriting textioc in assembly! I really like the new features you’ve added to it! I know very little about ASM, but I hope to learn it quickly in order to help rewrite the library. Very Happy


I'm very happy you noticed Smile
Also I'm exited you are receptive to my fork Very Happy

EDIT: finished rewrite, made a pull request.
EDIT2: NOTE on textio_LetterInput: My rewrite of that function does not have cursor scrolling yet.
Hello everyone!

I have written an outline for textioc to help figure out how all of the functions will work and how they should be implemented. If you are interested in helping with the library or have any questions about the outline, please PM me.

If you have any features you think would be useful, please let me know! Smile
Progress Update on TextIOC

As part of my next release of Mental Math CE, I am porting the TextIOC library to eZ80 assembly. After a discussion with DrDnar, the creator of the FontLibC library, I realized that TextIOC would be better implemented as a wrapper for the FontLib library, providing the text wrapping support DrDnar mentioned in his library documentation as well as providing the input function that the previous version supported. This change will mean that TextIOC will no longer support the GraphX font.

I have pulled the C version from Github and pushed the current ASM version to the TextIOC repository. This version is incomplete. I am still slowly rewriting functions from C into assembly.


Debugging an ASM Function

This post is also a request for help. Wink

The problem is in the following function: uint24_t textio_GetLineWidth(const char *line, const char *eol). The line parameter is a pointer to the start of the line, and the eol parameter is a pointer to the End-Of-Line. This is the current, unoptimized version:

Code:
 ;-------------------------------------------------------------
; Includes
;-------------------------------------------------------------
    include 'include/library.inc'
    include 'include/include_library.inc'


;-------------------------------------------------------------
    library 'TEXTIOC', 1
;-------------------------------------------------------------


;-------------------------------------------------------------
; Dependencies
;-------------------------------------------------------------
    include_library 'graphx.asm'
    include_library 'fontlibc.asm'


;-------------------------------------------------------------
; v1 functions
;-------------------------------------------------------------
    export textio_SetTabWidth
    export textio_GetTabWidth
    export textio_GetLineWidth


;-------------------------------------------------------------
; Global variables
;-------------------------------------------------------------
    arg0     := 3
    arg1     := 6
    null     := $00
    tab      := $09




;-------------------------------------------------------------
; Functions
;-------------------------------------------------------------


;-------------------------------------------------------------
textio_SetTabWidth:
; Arguments:
;   arg0 = width
; Returns:
;   None
; Destroys:
;   HL
;   DE

    pop     hl
    pop     de
    push    de
    push    hl
    ld     (_TabWidth), de
    ret

;-------------------------------------------------------------
textio_GetTabWidth:
; Arguments:
;   None
; Returns:
;   Width of tab

    ld       hl, (_TabWidth)
    ret
   

;-------------------------------------------------------------
textio_GetLineWidth:
; Arguments:
;   arg0  =  pointer to line
;   arg1  =  pointer to end of line
; Returns:
;   Width of line

    scf            ; dbg_Debugger()
    sbc     hl,hl
    ld     (hl),2
   
    ld      iy, 0
    add     iy, sp
    ld      hl, (iy + arg0)        ; hl -> line
    ld      bc, (iy + arg1)        ; bc -> eol

    ld      e, 0
    ld      d, 0

.loop:
    ld      a, (hl)
    cp      a, null
    jr      z, .exit

    push    hl
    sbc     hl, bc
    jr      z, .exit

    pop     hl
    ld      a, (hl)
    cp      a, tab
    jr      nz, .addGlyphWidth

    push    hl
    call    textio_GetTabWidth
    call    util.AddHLToDE
    pop     hl
    jr      .nextChar

.addGlyphWidth:
    push    de
    push    hl
    call    fontlib_GetGlyphWidth
    pop     hl
    pop     de
    call    util.AddAToDE

.nextChar:
    inc     hl        ; HL should be pointer to line
    jr      .loop

.exit:
    ex      de, hl
    ret



;-------------------------------------------------------------
; Internal Library Functions
;-------------------------------------------------------------


;-------------------------------------------------------------
util.AddAToDE:
; Inputs:
;   A  = Operand 1
;   HL = Operand 2
; Ouputs:
;   DE = DE + A

    add   a, e
    ld    e, a
    jr    nc, .exit
    inc   d
.exit:
    ret

;-------------------------------------------------------------
util.AddHLToDE:
; Inputs:
;   HL = Operand 1
;   DE = Operand 2
; Outputs:
;   DE = HL + DE

    push  hl
    add   hl, de
    ex    hl, de
    pop   hl
    ret




;-------------------------------------------------------------
; Internal Library Data
;-------------------------------------------------------------

_TabWidth:
    dl     4
_PrintFormat:
    db     0

The main function that calls it:

Code:
 #include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <tice.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include <graphx.h>
#include <debug.h>
#include "dbg/calcdbg.h"

#include <fileioc.h>
#include <fontlibc.h>
#include "fonts/fonts.h"

#include <textioc.h>


void textio_SetWindow_Outline(unsigned int x, uint8_t y, unsigned int width, uint8_t height) {
   
   gfx_SetColor(224);
   fontlib_SetWindow(x, y, width, height);
   gfx_Rectangle_NoClip(x, y, width + 1, height);
}


void main(void) {
   
    char text[] = {"\tThis is a very long sample string for wrapping around 320 pixels. This is yet another sample string made for text wrapping testing."};
   
   uint24_t width;

    gfx_Begin();
    fontlib_SetFont(test_font, 0);
   
    fontlib_SetLineSpacing(2, 2);
    textio_SetWindow_Outline(0, 0, 220, 240);
    fontlib_SetColors(0x00, 0xFF);
   
   //textio_SetTabWidth(4);
   
   //textio_SetPrintFormat(1);
    //textio_PrintText(text, 5);
   dbg_sprintf(dbgout, "tab = %d\n", textio_GetTabWidth());
   width = textio_GetLineWidth(text, text + 2);
   dbg_sprintf(dbgout, "line width = %d\n", width);
    while (!os_GetCSC());
   
    gfx_End();
}]

The first loop executes correctly, leaving DE as four (the width of the tab). The second loop, however, does not execute correctly as it adds only four to DE when it should add at least six for the “T”. During this loop, the accumulator holds $54 (“T”), so I think the bug lies somewhere around the call to fontlib_GetGlyphWidth. At the end of the third loop, the function exits, an invalid write to flash occurs, and the calculator crashes.

If anyone could show me where the bug lies, I would very much appreciate it!

GUILibCE Update

After a considerable amount of thinking and experimenting, I have concluded that creating a GUI library for the TI-84 Plus CE would not be feasible, given the enormous flexibility it would need to possess and my lack of time to bring the project to fruition. Laying this project aside, I have renamed this forum thread, and it will become the main development thread for the TextIOC library.
To DrDnar:

I believe I found what was giving us all the trouble. While I was getting the second code ready to run, I found that the copy of fontlibc.asm that I had gotten from your repository on Github did not have the fontlib_DrawUInt function that the code needed. Going to the toolchain repository, I found its copy of FontLib that included the function and replaced my copy with it. The code ran perfectly. I think that my using the wrong copy of FontLib was the problem.

On a side note, I noticed that the copy from your repo had ‘library FONTLIBC, 1’ in its header. Although I do not know what the syntax means (and would be happy to learn), I suspect that line could have made some subtle collisions occur with TextIOC which uses the same number.

The invalid write to flash still occurs when I run my function, but when I’m using the debugger and disassembler, I can recognize the FontLib code executing when I call fontlib_GetGlyphWidth. I know that my function is still sub-par (e.g. realizing I was passing a pointer instead of a char to fontlib_GetGlyphWidth in the above code Rolling Eyes ), but I feel confident that I can carry on and get this off the ground.

Thanks for all your help, I really appreciate it! Very Happy


Message to the Admins: On second thought, I think this thread should go into the “Your Projects” topic as it is a personal project and not a general ASM thread. Thanks!
To DrDnar:

While I was working on one of the TextIOC functions, I found that fontlib_GetStringWidth modified the stack in a strange way. The function that I was porting was textio_GetLinePtr, and the fontlib call is on line 290. This is the C code I was using as a reference to port the function:

Code:
 char *textio_GetLinePtr(const char *text, uint8_t line_num) {
   
   uint8_t curr_line_num;
   unsigned int line_width;
   
   char *curr_word;
   char *curr_line;
   
   fontlib_SetFirstPrintableCodePoint(0x20);
   fontlib_SetAlternateStopCode(' ');
   curr_line_num = 0;
   line_width = 0;
   curr_word = text;
   curr_line = curr_word;
   
   for (;;) {
      
      START:
      if (*fontlib_GetLastCharacterRead() == '\0')
         return fontlib_GetLastCharacterRead();
      
      if (curr_line_num == line_num)
         return curr_line;
      
      line_width += fontlib_GetStringWidth(curr_word);
      if (*fontlib_GetLastCharacterRead() == ' ')
         line_width += fontlib_GetGlyphWidth(' ');
      
      if (*fontlib_GetLastCharacterRead() == '\t') {
         line_width += textio_GetTabWidth();
      };
      
      if (line_width > fontlib_GetWindowWidth()) {
         curr_line_num++;
         line_width = 0;
         if (textio_print_config.format == RIGHT_MARGIN_FLUSH)
            curr_word--;
         curr_line = curr_word;
         goto START;
      };
      
      if (*fontlib_GetLastCharacterRead() == '\n') {
         curr_line_num++;
         line_width = 0;
         curr_line = fontlib_GetLastCharacterRead() + 1;
      };
      
      curr_word = fontlib_GetLastCharacterRead() + 1;
   };
}

Register HL holds a pointer to the current word being processed, register DE holds the current line width, and register BC holds a pointer to the start of the current line. Before the function call, the stack looks like this:

Code:
Address       Value         Register
---------     ------        ---------
D1A797        D1A7A9        HL
D1A79A        000000        DE
D1A79D        D1A7A9        BC


After the function call, the stack changes:

Code:
Address       Value         Register
---------     ------        ---------
D1A797        FFFFFF        HL
D1A79A        000000        DE
D1A79D        D1A7A9        BC


I couldn’t tell if this was intended behavior or not, but since it destroyed the value that was supposed to be popped into HL, the function froze the calculator when it executed. I then tried pushing HL twice before the function call, making the stack look like this:

Code:
Address       Value         Register
---------     ------        ---------
D1A794        D1A7A9        HL
D1A797        D1A7A9        HL
D1A79A        000000        DE
D1A79D        D1A7A9        BC


Stack state after the call:

Code:
Address       Value         Register
---------     ------        ---------
D1A794        FFFFFF        HL
D1A797        D1A7A9        HL
D1A79A        000000        DE
D1A79D        D1A7A9        BC


After the call, I popped the stack into HL twice to recover the proper value. The function worked after that ( still not returning the correct line pointer, yet Wink ).

I didn’t know if this was a bug or not, but I thought you should know about it.

EDIT: After a discussion with DrDnar, I learned that C assembly functions are not required to preserve passed arguments.
Progress Update

The textio_PrintText function is nearing completion. All that is left is the debugging of the print_centered and print_right_margin_flush flags. I am hoping to post a screenshot of the finished function soon. Smile

By bitter experience, I have found that to have a rock-solid outline of how a given function will work is indispensable and have written up an outline for the next major function, the textio_Input function. The file is hosted on my Google Drive in a PDF format. Any feedback on the design would be most appreciated!

Download: https://drive.google.com/file/d/1w4Qr_WomntPjzGtLdwdJViTFaofxt6yI/view?usp=sharing
About the GUI not being feasible on the CE- are you familiar with the GUI library available for the TI-83+ using DCS7? I used it for a utility and a game and really liked it.
Yes, I am familiar with the Doors GUI library. To create a similar library for the CE is definitely feasible.

While I was developing GUILibCE, I looked at several games and programs for the CE and thought about how each user interface would be implemented using a single GUI library. After awhile the sheer variability between each user interface made what I at first deemed a simple task into a massive project. In order for the programmer to customize at will each GUI element in the library, it would have to be very flexible and would require a level of expertise I do not possess. A brief research session on several computer widget toolkits, including OpenGL and Qt, finally convinced me that my vision had outgrown my skill, and I decided to drop the project in favor of TextIOC.

After I laid the project to rest, however, I did have another idea that may be useful if anyone would like to take it up: a computer-based GUI builder for the CE. It would use an interface like Microsoft Paint, supplying functions like rectangles, circles, and so on. The programmer would select the type of GUI element he wanted to create (e.g. a window) and then draw it. The GUI builder would keep track of each shape drawn, supply the necessary variables for width, height, x-position, and y-position, and translate the shapes into C code using the GraphX functions. Once the programmer was satisfied, the program would output the completed function (e.g. draw_window()), and the programmer could then incorporate it into his program or add it to his own personal GUI library.

The advantage of this kind of program is that it would allow the programmer to see what the finished element would look like in real-time, rather than going back-and-forth from source code to calculator trying to make it look right.
Progress Update

Here is the demo!


The pause when each "Printing..." message shows is a deliberate delay in the code. The actual print time for each screen is less than one second.

I have also updated the Github repo. If anyone has any bug reports, code recommendations, or suggestions, I would be more than happy to hear them! Very Happy
Captain Calc wrote:
Yes, I am familiar with the Doors GUI library. To create a similar library for the CE is definitely feasible.

While I was developing GUILibCE, I looked at several games and programs for the CE and thought about how each user interface would be implemented using a single GUI library. After awhile the sheer variability between each user interface made what I at first deemed a simple task into a massive project. In order for the programmer to customize at will each GUI element in the library, it would have to be very flexible and would require a level of expertise I do not possess. A brief research session on several computer widget toolkits, including OpenGL and Qt, finally convinced me that my vision had outgrown my skill, and I decided to drop the project in favor of TextIOC.

After I laid the project to rest, however, I did have another idea that may be useful if anyone would like to take it up: a computer-based GUI builder for the CE. It would use an interface like Microsoft Paint, supplying functions like rectangles, circles, and so on. The programmer would select the type of GUI element he wanted to create (e.g. a window) and then draw it. The GUI builder would keep track of each shape drawn, supply the necessary variables for width, height, x-position, and y-position, and translate the shapes into C code using the GraphX functions. Once the programmer was satisfied, the program would output the completed function (e.g. draw_window()), and the programmer could then incorporate it into his program or add it to his own personal GUI library.

The advantage of this kind of program is that it would allow the programmer to see what the finished element would look like in real-time, rather than going back-and-forth from source code to calculator trying to make it look right.



This is what I’ve been searching for. Captain Calc do you have a discord channel? Please pm me. I’m new here and interested in contributing the TI-84 community. I’m more proficient in java but I will do my best working with c.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are GMT - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement