CC65BuildSolution/TextSlides/TextSlides.c

408 lines
12 KiB
C

/* ------------------------------------------------------------------------
System : cc65 cross-development environment
Platform : Apple IIe
Program : TextSlides (C) Copyright Olivier Guinart 2015.
All rights reserved.
Description : Apple //e ProDOS 8 Text-based Slideshow Program
Written by : Olivier Guinart
Date Written : April 2015
Revision : 1.0 First Release (CC65)
Date Revised : xxxxx
Licence : You may use this program for whatever you wish as long
as you agree that Olivier Guinart has no warranty or
liability obligations whatsoever from said use.
------------------------------------------------------------------------ */
#ifndef __APPLE2__
#define __APPLE2__
#endif
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <errno.h>
#include <apple2enh.h>
#include "_file.h"
#define iMaxStrLen 256
#define ELLIPSIS "...\0" // Used to truncate the slide title if it's longer than screen width
unsigned char XSize, YSize; // Used to store screen size
int iSlidesPosition[iMaxStrLen]; // Used to store slides position within Diapos.txt for fseek purposes
char strTemp[iMaxStrLen]; // Temp string
int ch; // Temp char
int iPos; // Temp var that tracks the current line of the slides txt file
int iCurrentSlide; // Tracks the current slide being displayed
/* 1MHZ timing loop settings - increase for faster machines */
#define YTIME 60L
#define XTIME 2L
char wait(unsigned duration)
{
char c = 0;
long y, x;
while (duration > 0) {
for (y = 0; y < YTIME; y++) {
for (x = 0; x < XTIME; x++) {
if (kbhit()) {
c = cgetc();
/* clear keyboard buffer */
while (kbhit())cgetc();
return c;
}
}
}
duration--;
}
return c;
}
void sound(int duration, int pitch)
{
char *speaker = (char*) 0xC030;
int i, j;
char c;
for (i = 0; i < duration; i++)
{
c += *speaker;
for (j = 0; j < pitch; j++);
}
}
/* fgets for Apple II text files - read native apple II text files properly!
the cc65 version doesn't! Which means that you need to use unix text files
unless you roll your own fgets... */
/* Created in Windows, text file lines end with CRLF, chr(13) + chr(10) */
char* __fastcall__ fgets(char* s, unsigned size, register FILE* f)
{
register char* p = s;
unsigned i;
int c;
if (size == 0) {
/* Invalid size */
return (char*)_seterrno(EINVAL);
}
/* Read input */
i = 0;
c = fgetc(f);
while (c != EOF && ((char)c != (char)13)) {
//printf("'%i' ",c);
/* One char more */
*p = c;
++p;
++i;
c = fgetc(f);
}
if (c == EOF) {
// printf("DEBUG: in fgets with EOF%c",(char)13);
/* Error or EOF */
if ((f->f_flags & _FERROR) != 0 || i == 0) {
/* ERROR or EOF on first char */
// printf("DEBUG: in fgets returning %i%c",NULL,(char)13);
*p = '\0';
return NULL;
}
}
/* On lit le charactere LF, on l'ignore */
c = fgetc(f);
/* Terminate the string */
*p = '\0';
/* Done */
return s;
}
////////////////////////////////////////////////////////////////////////////////////
/// Repositions the file pointer to line iLine
/// iLine line number were the next read will happen
/// fp file from which to read the iBullets points
////////////////////////////////////////////////////////////////////////////////////
int PositionFilePointer(int iLine, FILE *fp)
{
int i;
// If we are here, it means we need to close the file, re-open it and reposition the pointer to the line #iLine...
fclose(fp);
/* We test/open the files of slides */
if ((fp = fopen("Diapos.txt", "r")) == NULL)
{
printf("Files 'Diapos.txt' couldn't be opened. Press a key to exit.");
cgetc();
return EXIT_FAILURE;
}
for (i = 1; i < iLine; i++)
{
fgets(strTemp, iMaxStrLen, fp);
}
return EXIT_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////
/// Print slide frame
///////////////////////////////////////////////////////////////////////////////
void SlideFrame()
{
/* Set screen colors, hide the cursor */
//textcolor(COLOR_WHITE);
//bordercolor(COLOR_BLACK);
//bgcolor(COLOR_BLACK);
//cursor(0);
/* Clear the screen, put cursor in upper left corner */
clrscr();
/* Draw a border around the screen */
/* Top line */
cputc(CH_ULCORNER);
chline(XSize - 2);
cputc(CH_URCORNER);
/* Vertical line, left side */
cvlinexy(0, 1, YSize - 2);
/* Bottom line */
cputc(CH_LLCORNER);
chline(XSize - 2);
cputc(CH_LRCORNER);
/* Vertical line, right side */
cvlinexy(XSize - 1, 1, YSize - 2);
}
///////////////////////////////////////////////////////////////////////////////
/// Slide #0 with title and subtitle of the presentation
/// strTitles, 2 strings arrays for title and subtitle
///////////////////////////////////////////////////////////////////////////////
void ShowOpeningSlide(char strTitles[2][iMaxStrLen])
{
int ilenTitle, ilenSubTitle, iMidX, iMidY;
ilenTitle = strlen(strTitles[0]);
ilenSubTitle = strlen(strTitles[1]);
// If Title and subtitle are empty, no need to even display an opening slides...
if ((ilenTitle + ilenSubTitle) > 0)
{
SlideFrame();
// printf("DEBUG: ilen '%i'%c", ilen, (char)13);
// printf("DEBUG: XSize '%i'%c", XSize, (char)13);
iMidX = XSize / 2;
iMidY = YSize / 2;
// printf("DEBUG: iMidX '%i'%c", iMidX, (char)13);
// Printing first the frame of the title
/* Vertical line, left side (x, y, longueur) */
// cvlinexy(iMidX - 2, 1, 1);
/* Ligne horizontale sous le texte */
// chlinexy(iMidX - 1, 2, ilen + 2);
/* Vertical line, right side */
// cvlinexy(iMidX + ilen + 1, 1, 1);
// Handling the title now, it will print from both right and left sides, animation effect...
gotoxy(iMidX - (ilenTitle / 2), iMidY - 4); // -4 to print a little bit above the middle
printf("%s", strTitles[0]);
gotoxy(iMidX - (ilenSubTitle / 2), iMidY);
printf("%s", strTitles[1]);
}
}
///////////////////////////////////////////////////////////////////////////////
/// Reads the slides file and call the ShowOpeningSlide procedure
/// strTitles, 2 strings arrays for title and subtitle
/// fp the slides text file
///////////////////////////////////////////////////////////////////////////////
int OpenAndShowOpeningSlide(char strTitles[2][iMaxStrLen], FILE *fp)
{
iPos = 0; // iPos will record the current line of the slides txt file
iCurrentSlide = 0;
PositionFilePointer(iPos, fp);
fgets(strTitles[0], iMaxStrLen, fp);
iPos++;
iSlidesPosition[iCurrentSlide] = iPos; // the opening slide is always on first (and second) line of the slides text file
fgets(strTitles[1], iMaxStrLen, fp);
iPos++;
ShowOpeningSlide(strTitles);
return cgetc();
}
///////////////////////////////////////////////////////////////////////////////
/// Print slide titles, below top frame line, centered and boxed
/// strTitle, the title of the slide read in Main() loop
///////////////////////////////////////////////////////////////////////////////
void SlideTitle(char strTitle[iMaxStrLen])
{
int i, j, ilen, iMidX;
int iMargin = 5;
register char* p;
ilen = strlen(strTitle);
// printf("DEBUG: ilen '%i'%c", ilen, (char)13);
// printf("DEBUG: XSize '%i'%c", XSize, (char)13);
// We need to test if the title is longer than the screen width + some buffer = 5
// If yes, we truncate with ellipsis...
if (ilen >= (XSize - iMargin))
{
p = strTitle + XSize - iMargin - strlen(ELLIPSIS);
memcpy(p, ELLIPSIS, strlen(ELLIPSIS));
ilen = strlen(strTitle);
}
iMidX = (XSize - ilen) / 2;
// printf("DEBUG: iMidX '%i'%c", iMidX, (char)13);
// printf("DEBUG: ilen = %i%c",ilen,(char)13);
// Printing first the frame of the title
/* Vertical line, left side (x, y, longueur) */
cvlinexy(iMidX - 2, 1, 1);
/* Ligne horizontale sous le texte */
chlinexy(iMidX - 1 , 2, ilen + 2);
/* Vertical line, right side */
cvlinexy(iMidX + ilen + 1, 1, 1);
// Handling the title now, it will print from both right and left sides, animation effect...
i = 0;
j = ilen - 1; // zero-index string array...
while (i <= j) {
gotoxy(iMidX + i, 1);
printf("%c", strTitle[i]);
gotoxy(iMidX + j, 1);
printf("%c", strTitle[j]);
sound(5, 30);
wait(1);
i++;
j--;
}
}
/////////////////////////////////////////////////////////////////////////////////////
/// Reads bullets from text files and prints them on screen, with margins x = 5, start y = 7
/// iBullets number of bullets/points of the slide
/// fp file from which to read the iBullets points
/////////////////////////////////////////////////////////////////////////////////////
void SlideBullets(int iBullets, FILE *fp)
{
const int iHmarge = 5;
const int iVmarge = 5;
int i;
for (i = 0; i < iBullets; i++) {
gotoxy(iHmarge, iVmarge + i);
fgets(strTemp, iMaxStrLen, fp);
printf("%s", strTemp);
}
}
////////////////////////////////////////////////////////////////////////////////////
/// Draws the whole slide
/// strTitle, the title of the slide read in Main() loop
/// iBullets number of bullets/points of the slide
/// fp file from which to read the iBullets points
////////////////////////////////////////////////////////////////////////////////////
void TitleAndContentSlide(char strTitle[iMaxStrLen], int iBullets, FILE *fp)
{
// We draw the frame of the slide
SlideFrame();
// We print the slide title
SlideTitle(strTitle);
// We load and print iBullets bullets from text file fp
SlideBullets(iBullets, fp);
}
////////////////////////////////////////////////////////////////////////////////////
/// Main :)
////////////////////////////////////////////////////////////////////////////////////
int main(void)
{
char strTitles[2][iMaxStrLen];
char strSlideTitle[iMaxStrLen];
int iBullets;
FILE *fp;
/* We test/open the files of slides */
if ((fp = fopen("Diapos.txt", "r")) == NULL) {
printf("Files 'Diapos.txt' couldn't be opened. Press a key to exit.");
cgetc();
return EXIT_FAILURE;
}
videomode(VIDEOMODE_80COL);
/* Ask for the screen size */
screensize(&XSize, &YSize);
// Slides are read from file
// File structure:
// 1st line = Presentation title (to be printed in Opening Slide)
// 2nd line = Presentation subtitle (to be printed in Opening Slide)
// 3rd line = Title of the first slide
// 4th line = n number of bullets for that slide
// n following lines = bullets of the slide
// Repeat with 3rd, 4th and n lines structure for next slides
ch = OpenAndShowOpeningSlide(strTitles, fp);
// First slide, First line = title...
while (fgets(strSlideTitle, iMaxStrLen, fp) != NULL) {
// We record the slide position in the slides text file
iCurrentSlide++;
iPos++; // +1 because of the title
// printf("DEBUG: iCurrentSlide='%i' iPos='%i'%c", iCurrentSlide, iPos, (char)13);
// cgetc();
iSlidesPosition[iCurrentSlide] = iPos; // We save the line position of the slide title
// Second line = Number of bullets in current slide...
fgets(strTemp, iMaxStrLen, fp);
iPos++; // +1 because of the count of bullets
// printf("DEBUG: strTemp '%s'%c", strTemp, (char)13);
iBullets = atoi(strTemp);
iPos+=iBullets; // And adding the bullets themselves
TitleAndContentSlide(strSlideTitle, iBullets, fp);
// We pause before going to next slide
ch = cgetc();
if (ch == CH_ESC) // If escape key pressed, exit loop
{
break;
}
if (ch == CH_CURS_LEFT) // Back to previous slide with left arrow letter (for now)
{
iCurrentSlide--;
if (iCurrentSlide > 0)
{
iPos = iSlidesPosition[iCurrentSlide];
PositionFilePointer(iPos, fp);
// When we entered the loop the first time, we weren't yet on the line, now we are, so
// to avoid counting it twice, we decrease it here by one...
iPos--;
// And same for the slide #...
iCurrentSlide--;
}
else
{
// we are back to the opening slide
// and we keep looping if users keeps pressing left arrow
ch = OpenAndShowOpeningSlide(strTitles, fp);
while (ch == CH_CURS_LEFT)
{
ch = cgetc();
};
// but we exit loop if ESC
if (ch == CH_ESC)
{
break;
}
}
}
}
// Close the file
fclose(fp);
clrscr();
return EXIT_SUCCESS;
}