https://bitbucket.org/daniel_fort/magic-lantern
Raw File
Tip revision: a8d69a387eb963d5ceedcb5a65b136d8ab2a8e84 authored by a1ex on 19 June 2016, 18:06:20 UTC
Close branch model-specific-icons.
Tip revision: a8d69a3
console.c
// script console

#include "bmp.h"
#include "dryos.h"
#include "menu.h"
#include "gui.h"
#include "property.h"
#include "config.h"
#include "zebra.h"
#include "shoot.h"

#ifdef CONFIG_QEMU
#include "qemu-util.h"
#endif

#ifndef CONFIG_CONSOLE
#error Something went wrong CONFIg_CONSOLE should be defined
#endif

#undef CONSOLE_DEBUG // logs things to file etc

#define CONSOLE_W 80
#define CONSOLE_H 21
#define CONSOLE_FONT FONT_MONO_20

// buffer is circular and filled with spaces
#define BUFSIZE (CONSOLE_H * CONSOLE_W)
static char console_buffer[BUFSIZE];
static int console_buffer_index = 0;
#define CONSOLE_BUFFER(i) console_buffer[MOD((i), BUFSIZE)]

int console_visible = 0;

static char console_help_text[40];
static char console_status_text[40];

void console_show()
{
    console_visible = 1;
    redraw();
}
void console_hide()
{
    console_visible = 0;
    msleep(100);
    canon_gui_enable_front_buffer(1);
}

void console_toggle()
{
    if (console_visible) console_hide();
    else console_show();
}

void console_set_help_text(char* msg)
{
    snprintf(console_help_text, sizeof(console_help_text), "     %s", msg);
}

void console_set_status_text(char* msg)
{
    snprintf(console_status_text, sizeof(console_status_text), "%s%s", msg, strlen(msg) ? "    " : "");
}
static void
console_toggle_menu( void * priv, int delta )
{
    if (console_visible) console_hide();
    else console_show();
}

#ifdef CONSOLE_DEBUG
static void
console_test( void * priv )
{
    console_visible = 1;
    printf("Hello World!\n");
    printf("The quick brown fox jumps over the lazy dog. Computer programs expand so as to fill the core available. El trabajo y la economia son la mejor loteria. \n");
}

static struct menu_entry script_menu[] = {
    {
        .name       = "Debug Console",
        .priv		= &console_visible,
        .select     = console_toggle_menu,
		.min		= 0,
		.max		= 1,
    },
};
#endif

void console_clear()
{
    int i;
    for (i = 0; i < BUFSIZE; i++)
        console_buffer[i] = ' ';
}

static void console_init()
{
    console_clear();

    #ifdef CONSOLE_DEBUG
    menu_add( "Debug", script_menu, COUNT(script_menu) );
    FIO_RemoveFile("ML/LOGS/console.log");
    #endif
}

void console_puts(const char* str) // don't DebugMsg from here!
{
    #define NEW_CHAR(c) CONSOLE_BUFFER(console_buffer_index++) = (c)
    
    #ifdef CONFIG_QEMU
    qprintf("%s", str);
    #endif

    #ifdef CONSOLE_DEBUG
    bmp_printf(FONT_MED, 0, 0, "%s ", str);

    FILE* f = FIO_CreateFileOrAppend("ML/LOGS/console.log");
    if (f)
    {
        FIO_WriteFile( f, str, strlen(str) );
        FIO_CloseFile(f);
    }
    //~ msleep(100);         /* uncomment this to troubleshoot things that lockup the camera - to make sure FIO tasks actually flushed everything */
    #endif

    /* for handling carriage returns */
    static int cr = 0;
    
    const char* c = str;
    while (*c)
    {
        if (*c == '\n')
        {
            if (MOD(console_buffer_index, CONSOLE_W) == 0)
                NEW_CHAR(' ');
            while (MOD(console_buffer_index, CONSOLE_W) != 0)
                NEW_CHAR(' ');
            cr = 0;
        }
        else if (*c == '\t')
        {
            NEW_CHAR(' ');
            while (MOD(console_buffer_index, 4) != 0)
                NEW_CHAR(' ');
        }
        else if (*c == '\b')
        {
            /* only erase on current line */
            if (MOD(console_buffer_index, CONSOLE_W) != 0)
            {
                console_buffer_index--;
                CONSOLE_BUFFER(console_buffer_index) = ' ';
            }
        }
        else if (*c == '\r')
        {
            cr = 1; /* will handle it later */
        }
        else
        {
            if (cr) /* need to handle a carriage return without line feed */
            {
                while (MOD(console_buffer_index, CONSOLE_W))
                    console_buffer_index--;
                cr = 0;
            }
            NEW_CHAR(*c);
        }
        c++;
    }
    
    console_buffer_index = MOD(console_buffer_index, BUFSIZE);
}

void console_show_status()
{
    int fnt = FONT(CONSOLE_FONT,60, COLOR_BLACK);
    bmp_printf(fnt, 0, 480 - font_med.height, console_status_text);
    if (console_visible) bmp_printf(fnt, 720 - font_med.width * strlen(console_help_text), 480 - font_med.height, console_help_text);
}

static void console_draw(int tiny)
{
    int cbpos0 = MOD((console_buffer_index / CONSOLE_W) * CONSOLE_W  + CONSOLE_W, BUFSIZE);
    
    /* display last two lines that actually contain something (don't display the cursor-only line) */
    if (tiny && console_buffer_index % CONSOLE_W == 0)
        cbpos0 -= CONSOLE_W;

    int skipped_lines = 0;
    int chopped_columns = 0;

    /* skip empty lines at the top */
    for (int i = 0; i < CONSOLE_H; i++)
    {
        int cbpos = cbpos0 + i * CONSOLE_W;
        int empty = 1;
        for (int j = 0; j < CONSOLE_W; j++)
            if (CONSOLE_BUFFER(cbpos + j) != ' ')
                { empty = 0; break; }
        if (empty) skipped_lines++;
        else break;
    }
    
    if (skipped_lines == CONSOLE_H) // nothing to show
        return;
    
    if (tiny)
        skipped_lines = CONSOLE_H - 3;
    
    /* chop empty columns from the right */
    for (int j = CONSOLE_W-1; j > 0; j--)
    {
        int empty = 1;
        for (int i = skipped_lines; i < CONSOLE_H; i++)
            if (CONSOLE_BUFFER(cbpos0 + i*CONSOLE_W + j) != ' ')
                { empty = 0; break; }
        if (empty) chopped_columns++;
        else break;
    }
    chopped_columns = MIN(chopped_columns, CONSOLE_W - (console_buffer_index % CONSOLE_W));
    
    if (skipped_lines < 5) skipped_lines = 0;
    if (chopped_columns < 5) chopped_columns = 0;

    /* top-left corner of "full" console (without lines/columns skipped) */
    unsigned x0 =  (chopped_columns < 7) ? 0 : 8;
    unsigned y0 =  480/2 - fontspec_font(CONSOLE_FONT)->height * CONSOLE_H/2;

    /* correct y to account for skipped lines */
    int yc = y0;
    if (tiny)
    {
        yc = gui_menu_shown() || MENU_MODE ? 415 : y0;
    }
    else
    {
        yc = y0 + fontspec_font(CONSOLE_FONT)->height * skipped_lines;
    }

    int fnt = FONT(CONSOLE_FONT,COLOR_WHITE, (lv || PLAY_OR_QR_MODE) ? COLOR_BG_DARK : COLOR_ALMOST_BLACK);

    int w = MIN((chopped_columns < 7) ? 720 : 704, fontspec_font(fnt)->width * (CONSOLE_W - chopped_columns) + 2);
    int h = fontspec_font(fnt)->height * (CONSOLE_H - skipped_lines);

    /* did the console shrink? if so, redraw Canon GUI around it */
    static int prev_w = 0;
    static int prev_h = 0;
    if (w < prev_w || h < prev_h)
    {
        canon_gui_enable_front_buffer(1); // force a redraw
        prev_w = w;
        prev_h = h;
        //return; // better luck next time :)
    }
    else if (!tiny)
        /* fixme: prevent Canon code from drawing over the console (ugly) */
        canon_gui_disable_front_buffer();
    prev_w = w;
    prev_h = h;

    /* display each line */
    int found_cursor = 0;
    int printed_width = 0;
    for (int i = skipped_lines; i < CONSOLE_H; i++)
    {
        char buf[CONSOLE_W+1];
        int cbpos = cbpos0 + i * CONSOLE_W;
        for (int j = 0; j < CONSOLE_W; j++)
        {
            // last character should be on last line => this ensures proper scrolling
            if (MOD(cbpos+j, BUFSIZE) == MOD(console_buffer_index, BUFSIZE)) // end of data
            {
                if (!found_cursor)
                {
                    buf[j] = '_';
                    found_cursor = 1;
                    continue;
                }
            }
            buf[j] = found_cursor ? ' ' : CONSOLE_BUFFER(cbpos+j);
            if (buf[j] == 0) buf[j] = '?';
        }
        buf[CONSOLE_W - chopped_columns] = 0;
        int y = yc + fontspec_font(fnt)->height * (i - skipped_lines);
        printed_width = bmp_printf(fnt | FONT_ALIGN_JUSTIFIED | FONT_TEXT_WIDTH(w), x0, y, "%s", buf);
    }
    
    bmp_draw_rect(60, x0-1, yc-1, printed_width+2, h+2);
    bmp_draw_rect(COLOR_BLACK, x0-2, yc-2, printed_width+4, h+4);

}

void console_draw_from_menu()
{
    if (console_visible)
        console_draw(1);
}

static void
console_task( void* unused )
{
    console_init();
    #ifdef CONSOLE_DEBUG
    console_show();
    #endif
    int dirty = 0;
    TASK_LOOP
    {
        // show the console only when there are no Canon dialogs on the screen
        if (console_visible && (display_idle() || is_pure_play_photo_or_movie_mode()))
        {
            if (dirty) console_draw(0);
            dirty = 1;
        }
        else if (dirty)
        {
            canon_gui_enable_front_buffer(1);
            dirty = 0;
        }
        else if (console_visible && !gui_menu_shown())
            console_draw(1);


        if (!gui_menu_shown() && strlen(console_status_text))
        {
            console_show_status();
        }

        msleep(200);
    }
}

TASK_CREATE( "console_task", console_task, 0, 0x1d, 0x1000 );

/* some functions from standard I/O */

int printf(const char* fmt, ...)
{
    char buf[512];
    va_list         ap;
    va_start( ap, fmt );
    int len = vsnprintf( buf, sizeof(buf)-1, fmt, ap );
    va_end( ap );
    console_puts(buf);
    return len;
}

int puts(const char * fmt)
{
    console_puts(fmt);
    console_puts("\n");
    return 0;
}
back to top