275 lines
7.5 KiB
C
275 lines
7.5 KiB
C
/*
|
|
* TilEm II
|
|
*
|
|
* Copyright (c) 2010-2011 Thibault Duponchelle
|
|
*
|
|
* This program is free software: you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <gtk/gtk.h>
|
|
#include <glib/gstdio.h>
|
|
#include <ticalcs.h>
|
|
#include <tilem.h>
|
|
|
|
#include "gui.h"
|
|
#include "filedlg.h"
|
|
#include "emucore.h"
|
|
|
|
|
|
/* Allocate a new TilemMacro structure which is empty */
|
|
static TilemMacro* tilem_macro_new() {
|
|
TilemMacro *macro = g_new(TilemMacro, 1);
|
|
macro->n = 0;
|
|
macro->actions = NULL;
|
|
return macro;
|
|
}
|
|
|
|
/* New or renew the table of actions (each TilemMacroAtom is an action) */
|
|
static TilemMacroAtom** tilem_macro_actions_new(TilemMacro *macro, int n) {
|
|
TilemMacroAtom **atom;
|
|
|
|
if(n == 0) {
|
|
atom = g_new(TilemMacroAtom*, n);
|
|
} else {
|
|
atom = g_renew(TilemMacroAtom*, macro->actions, n);
|
|
}
|
|
return atom;
|
|
}
|
|
|
|
/* Try to destroy the TilemMacro if really allocated */
|
|
static void tilem_macro_finalize(TilemMacro* macro) {
|
|
if(macro) {
|
|
if(macro->actions)
|
|
g_free(macro->actions);
|
|
g_free(macro);
|
|
}
|
|
}
|
|
|
|
/* Firstly free the memory then create a new TilemMacro */
|
|
void tilem_macro_start(TilemCalcEmulator *emu) {
|
|
emu->isMacroRecording = TRUE;
|
|
|
|
/* Firstly destroy the macro if exists */
|
|
tilem_macro_finalize(emu->macro);
|
|
|
|
/* Then allocate a new one */
|
|
emu->macro = tilem_macro_new(emu);
|
|
}
|
|
|
|
/* Add an action to the macro. The action could be :
|
|
* A keypress (type == 0)
|
|
* A file load (type == 1)
|
|
* Or something else if I implement it :)
|
|
*/
|
|
void tilem_macro_add_action(TilemMacro* macro, int type, char * value) {
|
|
|
|
int n = macro->n;
|
|
|
|
/* We want to allocate for 1 object, but index is 0 */
|
|
macro->actions = tilem_macro_actions_new(macro, n + 1);
|
|
|
|
/* Then we need to save the action */
|
|
macro->actions[n] = g_new(char, strlen(value)); /* FIXME : gcc says : "assignment from incompatible pointer type" ??? */
|
|
macro->actions[n]->value = g_strdup(value);
|
|
macro->actions[n]->type = type;
|
|
macro->n++;
|
|
}
|
|
|
|
/* Stop the macro */
|
|
void tilem_macro_stop(TilemCalcEmulator *emu)
|
|
{
|
|
if(emu->isMacroRecording)
|
|
emu->isMacroRecording = FALSE;
|
|
}
|
|
|
|
/* Print the macro actions content (debug) */
|
|
void tilem_macro_print(TilemMacro *macro) {
|
|
int i = 0;
|
|
|
|
printf("macro->n : %d\n", macro->n);
|
|
for(i = 0; i < macro->n; i++ ){
|
|
printf("type : %d value : %s\n", macro->actions[i]->type, macro->actions[i]->value);
|
|
}
|
|
}
|
|
|
|
/* Write a file using TilemMacro structure */
|
|
void tilem_macro_write_file(TilemCalcEmulator *emu) {
|
|
char *dir, *filename;
|
|
tilem_config_get("macro",
|
|
"directory/f", &dir,
|
|
NULL);
|
|
|
|
filename = prompt_save_file("Save macro",
|
|
GTK_WINDOW(emu->ewin->window),
|
|
NULL,
|
|
dir,
|
|
"Macro files", "*.txt",
|
|
"All files", "*",
|
|
NULL);
|
|
if(filename) {
|
|
FILE * fp = g_fopen(filename, "w");
|
|
if(fp) {
|
|
int i = 0;
|
|
for(i = 0; i< emu->macro->n; i++ ){
|
|
printf("type : %d value : %s\n", emu->macro->actions[i]->type, emu->macro->actions[i]->value);
|
|
/* Test if it's a key press or a file loading action */
|
|
if(emu->macro->actions[i]->type == 1) {
|
|
char * lengthchar = g_new0(char, 4);
|
|
int length = strlen(emu->macro->actions[i]->value);
|
|
fwrite("file=", 1, 5, fp);
|
|
sprintf(lengthchar, "%04d", strlen(emu->macro->actions[i]->value));
|
|
fwrite(lengthchar, 1, sizeof(int), fp);
|
|
fwrite("-", 1, 1, fp);
|
|
fwrite(emu->macro->actions[i]->value, 1, length, fp);
|
|
g_free(lengthchar);
|
|
} else {
|
|
fwrite(emu->macro->actions[i]->value, 1, 4, fp);
|
|
fwrite(",", 1, 1, fp);
|
|
}
|
|
}
|
|
tilem_config_set("macro", "directory/f", g_path_get_dirname(filename), NULL);
|
|
fclose(fp);
|
|
}
|
|
g_free(filename);
|
|
g_free(dir);
|
|
}
|
|
}
|
|
|
|
#define MACRO_KEYPRESS 0
|
|
#define MACRO_FILE 1
|
|
|
|
/* Play the macro (macro should be created or loaded before else it does nothing) */
|
|
static gboolean tilem_macro_play_main(TilemCalcEmulator *emu, G_GNUC_UNUSED gpointer data) {
|
|
|
|
if(!emu->macro) {
|
|
printf("Nothing to play\n");
|
|
return FALSE;
|
|
}
|
|
|
|
int i;
|
|
for(i = 0; i < emu->macro->n; i++ ){
|
|
if(emu->macro->actions[i]->type == MACRO_FILE) {
|
|
/* Type == 1 is load file */
|
|
struct TilemSendFileInfo *sf;
|
|
sf = g_slice_new0(struct TilemSendFileInfo);
|
|
sf->filename = g_strdup(emu->macro->actions[i]->value);
|
|
sf->display_name = g_filename_display_basename(emu->macro->actions[i]->value);
|
|
sf->slot = -1;
|
|
sf->first = TRUE;
|
|
sf->last = TRUE;
|
|
send_file_main(emu, sf);
|
|
|
|
} else {
|
|
/* type == 0 is keypress */
|
|
int code = atoi(emu->macro->actions[i]->value);
|
|
tilem_em_unlock(emu);
|
|
run_with_key_slowly(emu->calc, code);
|
|
tilem_em_lock(emu);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static void tilem_macro_play_finished(G_GNUC_UNUSED TilemCalcEmulator *emu, G_GNUC_UNUSED gpointer data,
|
|
G_GNUC_UNUSED gboolean cancelled) {
|
|
|
|
}
|
|
|
|
/* Play the macro */
|
|
void tilem_macro_play(TilemCalcEmulator* emu) {
|
|
|
|
tilem_calc_emulator_begin(emu, &tilem_macro_play_main, &tilem_macro_play_finished, NULL);
|
|
}
|
|
|
|
/* Load a macro (when finished, task manager will normally call tilem_macro_play) */
|
|
static gboolean tilem_macro_load_main(TilemCalcEmulator* emu, gpointer data) {
|
|
|
|
char* filename = (char*) data;
|
|
char c = 'a';
|
|
|
|
if(filename) {
|
|
FILE * fp = g_fopen(filename, "r");
|
|
/* printf("filename : %s\n", filename); */
|
|
|
|
tilem_macro_start(emu);
|
|
while(c != EOF) {
|
|
char* codechar = g_new0(char, 4);
|
|
fread(codechar, 1, 4, fp);
|
|
if(strcmp(codechar, "file") == 0) {
|
|
c = fgetc(fp); /* Drop the "="*/
|
|
char *lengthchar = g_new0(char, 4);
|
|
fread(lengthchar, 1, 4, fp);
|
|
c = fgetc(fp); /* Drop the "-"*/
|
|
int length = atoi(lengthchar);
|
|
char* filetoload= g_new0(char, length);
|
|
fread(filetoload, 1, length, fp);
|
|
tilem_macro_add_action(emu->macro, 1, filetoload);
|
|
g_free(lengthchar);
|
|
g_free(filetoload);
|
|
} else {
|
|
int code = atoi(codechar);
|
|
if(code <= 0)
|
|
break;
|
|
/*printf("code : %d, codechar : %s\n",code, codechar); */
|
|
tilem_macro_add_action(emu->macro, 0, codechar);
|
|
c = fgetc(fp);
|
|
}
|
|
}
|
|
tilem_macro_stop(emu);
|
|
fclose(fp);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* When the macro is totally loaded, then we can play it ! */
|
|
static void tilem_macro_load_finished(G_GNUC_UNUSED TilemCalcEmulator *emu, G_GNUC_UNUSED gpointer data,
|
|
G_GNUC_UNUSED gboolean cancelled)
|
|
{
|
|
tilem_calc_emulator_begin(emu, &tilem_macro_play_main, &tilem_macro_play_finished, NULL);
|
|
}
|
|
|
|
/* Load a macro from filename.
|
|
* If filename == NULL prompt the user
|
|
*/
|
|
void tilem_macro_load(TilemCalcEmulator *emu, char* filename) {
|
|
|
|
/* printf("tilem_macro_load : filename : %s\n", filename); */
|
|
if(!filename) {
|
|
char *dir;
|
|
tilem_config_get("macro", "directory/f", &dir, NULL);
|
|
|
|
filename = prompt_open_file("Open macro",
|
|
GTK_WINDOW(emu->ewin->window),
|
|
dir,
|
|
"Macro files", "*.txt",
|
|
"All files", "*",
|
|
NULL);
|
|
if(dir)
|
|
g_free(dir);
|
|
}
|
|
tilem_calc_emulator_begin(emu, &tilem_macro_load_main, &tilem_macro_load_finished, filename);
|
|
}
|
|
|