home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-05-31 | 27.5 KB | 1,044 lines |
- /*
- *
- * Title : Text display routines.
- * System : Any */
- #define Version "2.1"
- /* Copyright : (c) John H. Winters
- * Date : 7th October, 1992
- * Author : John H. Winters
- *
- * Function : Displays text in a window under Risc-OS.
- *
- *
- * Modification history.
- *
- * Version : 1.1
- * Date : 17th October, 1992
- * Author : John H. Winters
- * Changes : Implemented a more efficient way of scrolling the window.
- *
- * Version : 1.2
- * Date : 24th October, 1992
- * Author : John H. Winters
- * Changes : Added some defence against recursive calls.
- *
- * Version : 1.3
- * Date : 12th November, 1992
- * Author : John H. Winters
- * Changes : Added a visible cursor.
- *
- * Version : 2.0
- * Date : 23rd May, 1993
- * Author : John H. Winters
- * Changes : Ported to Risc OS 3.1
- *
- * Version : 2.1
- * Date : 31st May, 1993
- * Author : John H. Winters
- * Changes : New parameter to WIMP_ReportError
- *
- * Version :
- * Date :
- * Author :
- * Changes :
- *
- */
-
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
-
- #include "global.h"
- #if !defined (ARTHUR)
- #error This module is for Risc-OS only.
- #endif
- #include "vdu.h"
- #include "wimplib.h"
- #include "winapp.h"
- #include "logging.h"
- #include "linklist.h"
- #include "text.h"
-
- /*
- *============================================================================
- *
- * Hash defines.
- *
- *============================================================================
- */
-
- #define CHAR_HEIGHT 32
- #define CHAR_WIDTH 16
- #define CLG 16
- #define FLASH_INTERVAL 50
- #define LR_BORDER 4
- #define TB_BORDER 4
- #define TEMPLATE_FILE "Templates"
- #define TEMPLATE_NAME "TEXTWIN"
- #define Y_OFFSET 1
-
- /*
- *============================================================================
- *
- * Type definitions.
- *
- *============================================================================
- */
-
- typedef struct t_TXTI_Record {
- t_LL_Header header ;
- t_window_block *window_block ;
- t_window_handle window_handle ;
- uint visible ;
- uint cursor_on ;
- uint cursor_visible ;
- uint ticker_active ;
- uint height ;
- uint width ;
- /*
- * The next two are just to speed calculations.
- */
- uint osheight ;
- uint oswidth ;
- uint row ;
- uint col ;
- uint been_open ;
- } t_TXTI_Record ;
-
- /*
- * A little note on the visible, cursor_on and cursor_visible items in the
- * above data structure. This module implements a flashing cursor, which
- * the client code can activiate and deactivate. This leads to some
- * interesting messing about.
- *
- * visible is set to TRUE iff the window is currently open on the screen.
- * This doesn't necessarily mean that the window is actually visible to the
- * user, because it could be overlaid by another window. It does however
- * mean that we can sensibly make calls on routines to draw in the window.
- *
- * cursor_on is set to TRUE iff the client code has activated the visible
- * cursor.
- *
- * cursor_visible is meaningful iff both the preceding items are TRUE.
- * In that case, it indicates whether the flashing cursor is currently in
- * a "mark" state. If either of the other two is FALSE, then the cursor
- * is by implication invisible. Whenever we move to a state where both
- * the others are TRUE, cursor_visible is set to FALSE.
- *
- */
-
- /*
- *============================================================================
- *
- * Local data.
- *
- *============================================================================
- */
-
- static uint InEventHandler = FALSE ;
- static t_LL_Header RecordAnchor = LL_EMPTY ;
- static uint TemplateLoaded = FALSE ;
-
- /*
- *============================================================================
- *
- * Forward declarations.
- *
- *============================================================================
- */
-
- static void ActivateCursor (
- t_TXT_Handle handle) ;
-
- static void DeactivateCursor (
- t_TXT_Handle handle) ;
-
- static uint EventHandler (
- t_poll_block *poll_block,
- void *reference) ;
-
- static uint HandleValid (
- t_TXT_Handle handle) ;
-
- static void PlotCursor (
- t_TXT_Handle handle) ;
-
- static void RedrawWindow (
- t_TXT_Handle handle,
- t_redraw_block *r) ;
-
- static void TickerHandler (
- void *reference) ;
-
- /*
- *============================================================================
- *
- * Externally visible routines.
- *
- *============================================================================
- */
-
- void TXT_CursorOff (
- t_TXT_Handle handle)
-
- /*
- * Function :
- * Turn the flashing cursor off.
- *
- * Parameters :
- * handle Handle on the relevant window.
- *
- * Returns :
- * None.
- *
- */
-
- {
- if (HandleValid (handle))
- {
- if (handle->cursor_on)
- {
- handle->cursor_on = FALSE ;
- if (handle->visible)
- {
- DeactivateCursor (handle) ;
- }
- }
- }
- else
- {
- LOG_Warning ("TXT: Invalid handle passed to TXT_CursorOff.\n") ;
- }
- }
-
-
- void TXT_CursorOn (
- t_TXT_Handle handle)
-
- /*
- * Function :
- * Turn the cursor on in a text window.
- *
- * Parameters :
- * handle The handle of the window to turn it on in.
- *
- * Returns :
- * None.
- *
- */
-
- {
- if (HandleValid (handle))
- {
- if (!handle->cursor_on)
- {
- handle->cursor_on = TRUE ;
- if (handle->visible)
- {
- ActivateCursor (handle) ;
- }
- }
- }
- else
- {
- LOG_Warning ("TXT: Invalid handle passed to TXT_CursorOn.\n") ;
- }
- }
-
-
- t_TXT_Handle TXT_CreateWindow (
- uint height,
- uint width)
-
- /*
- * Function :
- * Create a text window (conceptually) for later use.
- *
- * Parameters :
- * height Height of the window in characters.
- * width Width of the window in characters.
- *
- * Returns :
- * Handle on the new structure, or NULL if not succesful.
- *
- */
-
- {
- u8 *body ;
- t_TXTI_Record *current ;
- t_box extent ;
-
- if (TemplateLoaded)
- {
- current = malloc (sizeof (t_TXTI_Record) + (height * width)) ;
- if (current == NULL)
- {
- LOG_Error ("TXT: Can't allocate memory for a text window.\n") ;
- }
- else
- {
- if (WA_CreateWindow (TEMPLATE_NAME,
- &(current->window_block),
- &(current->window_handle)))
- {
- if (WA_ClaimEvent (DONT_CARE,
- current->window_handle,
- DONT_CARE,
- EventHandler,
- current))
- {
- LL_InitHeader (&(current->header)) ;
- current->visible = FALSE ;
- current->cursor_on = FALSE ;
- current->cursor_visible = FALSE ;
- current->ticker_active = FALSE ;
- current->height = height ;
- current->width = width ;
- current->osheight = height * CHAR_HEIGHT ;
- current->oswidth = width * CHAR_WIDTH ;
- current->row = 0 ;
- current->col = 0 ;
- current->been_open = FALSE ;
- LL_AddToHead (&RecordAnchor,
- &(current->header)) ;
- body = (u8 *) (current + 1) ;
- memset (body, ' ', width * height) ;
- /*
- * Calculate the required extent. The two multipliers
- * are specified by Acorn and are constant (PRM P.1149)
- */
- extent.min.x = 0 - LR_BORDER ;
- extent.min.y = -(current->osheight) - TB_BORDER ;
- extent.max.x = current->oswidth + LR_BORDER ;
- extent.max.y = 0 + TB_BORDER ;
- LOG_OSError (WIMP_SetExtent (current->window_handle,
- &extent)) ;
- return (current) ;
- }
- else
- {
- LOG_Error ("TXT: Failed to claim window events.\n") ;
- }
- WA_DeleteWindow (current->window_handle) ;
- }
- else
- {
- LOG_Error ("TXT: Failed to create window.\n") ;
- }
- free (current) ;
- }
- }
- else
- {
- LOG_Error ("TXT: Can't create a window because the template is not loaded.\n") ;
- LOG_Error ("TXT: Use TXT_LoadResources during initialisation.\n") ;
- }
- return (NULL) ;
- }
-
-
- uint TXT_DisplayWindow (
- t_TXT_Handle handle)
-
- /*
- * Function :
- * Make our window actually appear on the screen.
- *
- * Parameters :
- * handle Handle on the window to display.
- *
- * Returns :
- * TRUE if we succeed, FALSE otherwise.
- *
- */
-
- {
- uint result ;
- t_state_block state ;
-
- result = FALSE ;
- if (InEventHandler)
- {
- result = TRUE ;
- }
- else
- {
- if (HandleValid (handle))
- {
- if (handle->visible)
- {
- result = TRUE ;
- }
- else
- {
- if (LOG_OSError (WIMP_GetWindowState (handle->window_handle,
- &state)) == NULL)
- {
- if (!handle->been_open)
- {
- state.open_block.scroll_offset.y = TB_BORDER ;
- state.open_block.scroll_offset.x = -LR_BORDER ;
- }
- if (LOG_OSError (WIMP_OpenWindow (&state.open_block)) == NULL)
- {
- handle->visible = TRUE ;
- handle->been_open = TRUE ;
- if (handle->cursor_on)
- {
- ActivateCursor (handle) ;
- }
- result = TRUE ;
- }
- }
- }
- }
- else
- {
- LOG_Warning ("TXT: Invalid handle passed to TXT_DisplayWindow.\n") ;
- }
- }
- return (result) ;
- }
-
-
- void TXT_HideWindow (
- t_TXT_Handle handle)
-
- /*
- * Function :
- * Remove our window from the screen.
- *
- * Parameters :
- * handle Handle on the window to remove.
- *
- * Returns :
- * None.
- *
- */
-
- {
- if (HandleValid (handle))
- {
- if (handle->visible)
- {
- LOG_OSError (WIMP_CloseWindow (handle->window_handle)) ;
- handle->visible = FALSE ;
- if (handle->cursor_on)
- {
- DeactivateCursor (handle) ;
- }
- }
- }
- else
- {
- LOG_Warning ("TXT: Invalid handle passed to TXT_HideWindow.\n") ;
- }
- }
-
-
- uint TXT_LoadResources (void)
-
- /*
- * Function :
- * Load the template required by TEXT.
- *
- * Parameters :
- * None.
- *
- * Returns :
- * TRUE for success, FALSE for failure.
- *
- */
-
- {
- if (WA_LoadTemplate (TEMPLATE_FILE,
- TEMPLATE_NAME))
- {
- TemplateLoaded = TRUE ;
- return (TRUE) ;
- }
- else
- {
- LOG_Error ("TXT: Unable to load required template.\n") ;
- return (FALSE) ;
- }
- }
-
-
- void TXT_PutText (
- t_TXT_Handle handle,
- const u8 *text)
-
- /*
- * Function :
- * Put text to a text window.
- *
- * Parameters :
- * handle Handle of the window to put to.
- * text Null-terminated text to put.
- *
- * Returns :
- * None.
- *
- */
-
- {
- u8 *body ;
- uint col ;
- const u8 *cr ;
- const u8 *current ;
- u8 *dest ;
- _kernel_oserror eb ;
- t_error_flags ef ;
- uint index ;
- uint len ;
- uint more ;
- t_point origin ;
- t_redraw_block r ;
- uint result ;
- uint row ;
- t_box source ;
- uint space ;
- uint to_put ;
-
- /*
- * We need a little check here against recursive calls. I know there is
- * already an external check, but there is one possibility that it won't
- * cope with. If we got an action message from Risc-OS, and encountered
- * a problem, we may have generated a log message. This log message will
- * eventually end up back here, and we could find ourselves trying to
- * update the window in the middle of doing something else. Hence our
- * little check.
- */
- if (InEventHandler)
- {
- /*
- * Use an error box instead.
- */
- eb.errnum = 1 ;
- strncpy (eb.errmess,
- text,
- 251) ;
- eb.errmess [251] = '\0' ;
- ef.value = 0 ;
- ef.m.ok = TRUE ;
- WIMP_ReportError (&eb, ef, "TXT", &result) ;
- }
- else
- {
- if (HandleValid (handle))
- {
- col = handle->col ;
- row = handle->row ;
- body = (u8 *) (handle + 1) ;
- current = text ;
- while ((len = strlen (current)) > 0)
- {
- space = handle->width - col ;
- cr = strchr (current, '\n') ;
- if (cr == NULL)
- {
- if (len > space)
- {
- to_put = space ;
- }
- else
- {
- to_put = len ;
- }
- }
- else
- {
- if ((cr - current) > space)
- {
- to_put = space ;
- }
- else
- {
- to_put = cr - current ;
- }
- }
- /*
- * Put the characters in the buffer.
- */
- dest = body + (row * handle->width) + col ;
- for (index = 0; index < to_put; index++)
- {
- if (current [index] < ' ')
- {
- dest [index] = ' ' ;
- }
- else
- {
- dest [index] = current [index] ;
- }
- }
- if (handle->visible)
- {
- if ((handle->cursor_on) &&
- (handle->cursor_visible))
- {
- PlotCursor (handle) ;
- handle->cursor_visible = FALSE ;
- }
- /*
- * Paint the relevant bit of screen.
- */
- r.handle = handle->window_handle ;
- r.visible_area.min.x = CHAR_WIDTH * col ;
- r.visible_area.min.y = -(CHAR_HEIGHT * (row + 1)) ;
- r.visible_area.max.x = r.visible_area.min.x + (CHAR_WIDTH * to_put) ;
- r.visible_area.max.y = r.visible_area.min.y + CHAR_HEIGHT ;
- if (LOG_OSError (WIMP_UpdateWindow (&r, &more)) == NULL)
- {
- while (more)
- {
- origin.x = r.visible_area.min.x - r.scroll_offset.x ;
- origin.y = r.visible_area.max.y - r.scroll_offset.y ;
- /*
- * Cursor to start.
- */
- VDU (CLG) ;
- VDU_Move (origin.x + (CHAR_WIDTH * col),
- origin.y - (CHAR_HEIGHT * row) - Y_OFFSET) ;
- for (index = 0; index < to_put; index++)
- {
- VDU (dest [index]) ;
- }
- WIMP_GetRectangle (&r, &more) ;
- }
- }
- }
- /*
- * Adjust the cursor position.
- */
- if (current [to_put] == '\n')
- {
- to_put++ ;
- col = 0 ;
- row++ ;
- }
- else
- {
- col += to_put ;
- if (col >= handle->width)
- {
- col = 0 ;
- row++ ;
- }
- }
- current += to_put ;
- /*
- * Do we need to scroll?
- */
- if (row >= handle->height)
- {
- if (handle->visible)
- {
- /*
- * All we do is tell the system to scroll by way of a WIMP_BlockCopy.
- * Risc-OS takes care of the rest.
- */
- source.min.x = 0 ;
- source.min.y = 0 - handle->osheight ;
- source.max.x = handle->oswidth ;
- source.max.y = 0 - CHAR_HEIGHT ;
- LOG_OSError (WIMP_BlockCopy (handle->window_handle,
- &source,
- 0,
- CHAR_HEIGHT - handle->osheight)) ;
- /*
- * Blank out the new bottom line.
- */
- r.handle = handle->window_handle ;
- r.visible_area.min.x = 0 ;
- r.visible_area.min.y = 0 - handle->osheight ;
- r.visible_area.max.x = handle->oswidth ;
- r.visible_area.max.y = r.visible_area.min.y + CHAR_HEIGHT ;
- if (LOG_OSError (WIMP_UpdateWindow (&r, &more)) == NULL)
- {
- while (more)
- {
- VDU (CLG) ;
- WIMP_GetRectangle (&r, &more) ;
- }
- }
- }
- memmove (body,
- body + handle->width,
- (handle->height - 1) * handle->width) ;
- memset (body + ((handle->height - 1) * handle->width),
- ' ',
- handle->width) ;
- row-- ;
- }
- }
- handle->col = col ;
- handle->row = row ;
- if ((handle->visible) &&
- (handle->cursor_on))
- {
- PlotCursor (handle) ;
- handle->cursor_visible = TRUE ;
- }
- }
- else
- {
- LOG_Warning ("TXT: Invalid handle passed to TXT_PutText.\n") ;
- }
- }
- }
-
-
- void TXT_SetCursor (
- t_TXT_Handle handle,
- uint row,
- uint column)
-
- /*
- * Function :
- * Set the cursor position in a text window.
- *
- * Parameters :
- * handle Handle of window.
- * row Row to put it in.
- * column Column to put it in.
- *
- * Returns :
- * None.
- *
- */
-
- {
- if (HandleValid (handle))
- {
- if (row >= handle->height)
- {
- LOG_Warning ("TXT: Attempt to set cursor to row %d of %d.\n") ;
- row = handle->height - 1 ;
- }
- if (column >= handle->width)
- {
- LOG_Warning ("TXT: Attempt to set cursor to column %d of %d.\n") ;
- column = handle->width - 1 ;
- }
- handle->row = row ;
- handle->col = column ;
- }
- else
- {
- LOG_Warning ("TXT: Invalid handle passed to TXT_SetCursor.\n") ;
- }
- }
-
- /*
- *============================================================================
- *
- * Private routines.
- *
- *============================================================================
- */
-
- static void ActivateCursor (
- t_TXT_Handle handle)
-
- /*
- * Function :
- * Activate the cursor in a window. Should only
- * be called if the window is visible on the screen.
- *
- * Parameters :
- * handle Handle on the window.
- *
- * Returns :
- * None.
- *
- */
-
- {
- handle->cursor_visible = FALSE ;
- if (WA_AlarmEvery (FLASH_INTERVAL,
- FALSE,
- TickerHandler,
- handle))
- {
- handle->ticker_active = TRUE ;
- }
- else
- {
- LOG_Error ("TXT: Failed to start ticker for cursor flash.\n") ;
- /*
- * Use a solid cursor.
- */
- PlotCursor (handle) ;
- handle->cursor_visible = TRUE ;
- }
- }
-
-
- static void DeactivateCursor (
- t_TXT_Handle handle)
-
- /*
- * Function :
- * Deactivate the cursor in a window. Should only
- * be called if the window is visible on the screen.
- *
- * Parameters :
- * handle Handle on the relevant window.
- *
- * Returns :
- * None.
- *
- */
-
- {
- if (handle->ticker_active)
- {
- WA_CancelAlarm (TickerHandler, handle) ;
- handle->ticker_active = FALSE ;
- }
- if (handle->cursor_visible)
- {
- PlotCursor (handle) ;
- handle->cursor_visible = FALSE ;
- }
- }
-
-
- static uint EventHandler (
- t_poll_block *poll_block,
- void *reference)
-
- /*
- * Function :
- * Handle events for our text windows.
- *
- * Parameters :
- * poll_block Pointer to poll block describing event.
- * reference Pointer to our record.
- *
- * Returns :
- * TRUE if we handled the event, FALSE otherwise.
- *
- */
-
- {
- t_TXTI_Record *current ;
- const _kernel_oserror *error_ptr ;
- uint more ;
- t_redraw_block r ;
- uint result ;
-
- InEventHandler = TRUE ;
- result = FALSE ;
- current = reference ;
- switch (poll_block->event_type)
- {
- case ET_RedrawRequest :
- r.handle = poll_block->data.ob.window_handle ;
- error_ptr = WIMP_RedrawWindow (&r, &more) ;
- if (error_ptr == NULL)
- {
- while (more)
- {
- RedrawWindow (current, &r) ;
- WIMP_GetRectangle (&r, &more) ;
- }
- }
- else
- {
- LOG_OSError (error_ptr) ;
- }
- result = TRUE ;
- break ;
-
- case ET_OpenRequest :
- LOG_OSError (WIMP_OpenWindow (&poll_block->data.ob)) ;
- result = TRUE ;
- break ;
-
- case ET_CloseRequest :
- LOG_OSError (WIMP_CloseWindow (current->window_handle)) ;
- if (current->visible)
- {
- current->visible = FALSE ;
- if (current->cursor_on)
- {
- DeactivateCursor (current) ;
- }
- }
- result = TRUE ;
- break ;
-
- }
- InEventHandler = FALSE ;
- return (result) ;
- }
-
-
- static uint HandleValid (
- t_TXT_Handle handle)
-
- /*
- * Function :
- * Check whether a window handle is valid.
- *
- * Parameters :
- * handle Handle to check.
- *
- * Returns :
- * TRUE if it is, FALSE if it isn't.
- *
- */
-
- {
- return (LL_InList (&RecordAnchor, &(handle->header))) ;
- }
-
-
- static void PlotCursor (
- t_TXT_Handle handle)
-
- /*
- * Function :
- * Plot the cursor in a window. This is done using
- * a block XOR, so this routine toggles it - off if on
- * and on if off.
- *
- * Parameters :
- * handle Handle of the window to plot in.
- *
- * Returns :
- * None.
- *
- */
-
- {
- uint more ;
- t_redraw_block r ;
-
- r.handle = handle->window_handle ;
- r.visible_area.min.x = CHAR_WIDTH * handle->col ;
- r.visible_area.min.y = -(CHAR_HEIGHT * (handle->row + 1)) ;
- r.visible_area.max.x = r.visible_area.min.x + CHAR_WIDTH ;
- r.visible_area.max.y = r.visible_area.min.y + CHAR_HEIGHT ;
- if (LOG_OSError (WIMP_UpdateWindow (&r, &more)) == NULL)
- {
- while (more)
- {
- /*
- * XOR one character position.
- */
- VDU_Gcol (3, 135) ;
- VDU (CLG) ;
- WIMP_GetRectangle (&r, &more) ;
- }
- }
- }
-
-
- static void RedrawWindow (
- t_TXT_Handle handle,
- t_redraw_block *r)
-
- /*
- * Function :
- * Redraw part or all of a window.
- *
- * Parameters :
- * handle Our handle on window to redraw.
- * r Redraw block defining required area.
- *
- * Returns :
- * None.
- *
- */
-
- {
- const u8 *body ;
- uint col ;
- const u8 *line ;
- sint maxrow ;
- sint minrow ;
- t_point origin ;
- sint row ;
- t_box vwa ;
-
- origin.x = r->visible_area.min.x - r->scroll_offset.x ;
- origin.y = r->visible_area.max.y - r->scroll_offset.y ;
- body = (u8 *) (handle + 1) ;
- /*
- * Calculate which rows require re-drawing.
- */
- vwa.min.x = r->graphics_window.min.x - r->visible_area.min.x + r->scroll_offset.x ;
- vwa.max.x = vwa.min.x + (r->graphics_window.max.x - r->graphics_window.min.x) ;
- vwa.max.y = r->graphics_window.max.y - r->visible_area.max.y + r->scroll_offset.y ;
- vwa.min.y = vwa.max.y - (r->graphics_window.max.y - r->graphics_window.min.y) ;
- minrow = (-vwa.max.y) / CHAR_HEIGHT ;
- if (vwa.min.y == 0)
- {
- maxrow = -1 ;
- }
- else
- {
- maxrow = ((- vwa.min.y - 1) / CHAR_HEIGHT) ;
- }
- if (maxrow >= (sint) handle->height)
- {
- maxrow = (sint) (handle->height - 1) ;
- }
- for (row = minrow; row <= maxrow; row++)
- {
- /*
- * Cursor to start.
- */
- VDU_Move (origin.x, origin.y - (CHAR_HEIGHT * row) - Y_OFFSET) ;
- line = body + (row * handle->width) ;
- for (col = 0; col < handle->width; col++)
- {
- VDU (line [col]) ;
- }
- }
- /*
- * Check the cursor position.
- */
- if ((handle->cursor_on) &&
- (handle->cursor_visible) &&
- (handle->row >= minrow) &&
- (handle->row <= maxrow))
- {
- /*
- * Redo the cursor position.
- */
- VDU_Gcol (3, 7) ;
- VDU_Move (origin.x + (CHAR_WIDTH * handle->col),
- origin.y - (CHAR_HEIGHT * (handle->row + 1))) ;
- VDU_Plot (97, CHAR_WIDTH - 1, CHAR_HEIGHT - 1) ;
- }
- }
-
-
- static void TickerHandler (
- void *reference)
-
- /*
- * Function :
- * Flash the cursor for a window.
- *
- * Parameters :
- * reference Window handle for the relevant window.
- *
- * Returns :
- * None.
- *
- */
-
- {
- t_TXT_Handle handle ;
-
- handle = reference ;
- PlotCursor (handle) ;
- handle->cursor_visible = !handle->cursor_visible ;
- }
-