408 lines
12 KiB
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;
|
||
|
}
|