https://bitbucket.org/coutts/5dplus
Raw File
Tip revision: 0d7cbec6dea8a278a468d89a5bf23bf5670a3172 authored by Coutts on 21 June 2012, 12:32:49 UTC
Fix font sizes (thanks Alex!) and fixed problem of bmp_buffer moving around, using a pointer to the bmp_vram now instead of the raw address. Also testing ML menu with skeleton shoot menu, not working yet though.
Tip revision: 0d7cbec
menu.c
/**
 * Magic Lantern GUI
 */
/*
 * Copyright (C) 2009 Trammell Hudson <hudson+ml@osresearch.net>
 * 
 * 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 2
 * 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, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301, USA.
 */

#include "vxworks.h"
#include "bmp.h"
#include "gui.h"
#include "font.h"
#include "menu.h"
#include "debug.h"



static int lv = 0;
static int advanced_mode = 1;
static int menu_first_by_icon = ICON_i;
static int sensor_cleaning = 0;
static int recording = 0;
static int hdmi_code = 0;
static int menu_upside_down = 0;

static struct semaphore * menu_sem;
extern struct semaphore * gui_sem;
static struct semaphore * menu_redraw_sem;
static int menu_damage;
static int menu_shown = false;
static int show_only_selected; // for ISO, kelvin...
static int config_dirty = 0;
static char* warning_msg = 0;
int menu_help_active = 0;
int submenu_mode = 0;
static int menu_id_increment = 1;
static int hist_countdown = 3; // histogram is slow, so draw it less often
static void select_menu_by_icon(int icon);
static void menu_help_go_to_selected_entry(struct menu * menu);
static void menu_show_version(void);
static struct menu * get_current_submenu();
static struct menu * get_selected_menu();
static struct menu * menus;


int is_movie_mode() { return 0; }


void menu_open_submenu(struct menu_entry * entry)
{
    submenu_mode = 1;
}

void
menu_binary_toggle(
                   void *          priv,
                   int unused
                   )
{
    unsigned * val = priv;
    *val = !*val;
}

void menu_ternary_toggle(void* priv, int delta)
{
    unsigned * val = priv;
    *val = mod(*val + delta, 3);
}

void menu_quaternary_toggle(void* priv, int delta)
{
    unsigned * val = priv;
    *val = mod(*val + delta, 4);
}

void menu_quinternary_toggle(void* priv, int delta)
{
    unsigned * val = priv;
    *val = mod(*val + delta, 5);
}

void menu_numeric_toggle(int* val, int delta, int min, int max)
{
    *val = mod(*val - min + delta, max - min + 1) + min;
}


static void entry_draw_icon(
                            struct menu_entry * entry,
                            int         x,
                            int         y
                            )
{
    if (entry->icon_type == IT_AUTO)
    {
        if (entry->select == menu_open_submenu)
        {
            entry->icon_type = IT_SUBMENU;
        }
        else if (!entry->priv || entry->select == (void(*)(void*,int))run_in_separate_task)
        {
            entry->icon_type = IT_ACTION;
        }
        else if(entry->choices)
        {
            const char* first_choice = entry->choices[0];
            if (streq(first_choice, "OFF") || streq(first_choice, "Hide"))
                entry->icon_type = IT_BOOL;
            else if (streq(first_choice, "ON"))
                entry->icon_type = IT_BOOL_NEG;
            else if (streq(first_choice, "Small"))
                entry->icon_type = IT_SIZE;
            else
                entry->icon_type = IT_DICE;
        }
        else if (entry->min != entry->max)
        {
            entry->icon_type = entry->max == 1 && entry->min == 0 ? IT_BOOL : IT_PERCENT;
        }
        else
            entry->icon_type = IT_BOOL;
    }
    
    switch (entry->icon_type)
    {
        case IT_BOOL:
            menu_draw_icon(x, y, MNI_BOOL(MEM(entry->priv)), 0);
            break;
            
        case IT_BOOL_NEG:
            menu_draw_icon(x, y, MNI_BOOL(!MEM(entry->priv)), 0);
            break;
            
        case IT_ACTION:
            menu_draw_icon(x, y, MNI_ACTION, 0);
            break;
            
        case IT_ALWAYS_ON:
            menu_draw_icon(x, y, MNI_ON, 0);
            break;
            
        case IT_SIZE:
            menu_draw_icon(x, y, MNI_SIZE, MEM(entry->priv) | ((entry->max+1) << 16));
            break;
            
        case IT_DICE:
            menu_draw_icon(x, y, MNI_DICE, MEM(entry->priv) | ((entry->max+1) << 16));
            break;
            
        case IT_PERCENT:
            menu_draw_icon(x, y, MNI_PERCENT, (MEM(entry->priv) - entry->min) * 100 / (entry->max - entry->min));
            break;
            
        case IT_NAMED_COLOR:
            menu_draw_icon(x, y, MNI_NAMED_COLOR, (intptr_t) entry->choices[MEM(entry->priv)]);
            break;
            
        case IT_DISABLE_SOME_FEATURE:
            menu_draw_icon(x, y, MEM(entry->priv) ? MNI_DISABLE : MNI_NEUTRAL, 0);
            break;
            
        case IT_DISABLE_SOME_FEATURE_NEG:
            menu_draw_icon(x, y, MEM(entry->priv) ? MNI_NEUTRAL : MNI_DISABLE, 0);
            break;
            
        case IT_REPLACE_SOME_FEATURE:
            menu_draw_icon(x, y, MEM(entry->priv) ? MNI_ON : MNI_NEUTRAL, 0);
            break;
            
        case IT_SUBMENU:
        {
            int value = 0;
            if (entry->priv) value = MEM(entry->priv); // if priv field is present, use it as boolean value
            else 
            {   // otherwise, look in the children submenus; if one is true, then submenu icon is drawn as "true"
                struct menu_entry * e = entry->children;
                for( ; e ; e = e->next )
                {
                    if( e->priv && MEM(e->priv))
                    {
                        value = 1;
                        break;
                    }
                }
                
            }
            menu_draw_icon(x, y, MNI_SUBMENU, value);
            break;
        }
    }
}


//------
int raw2iso( int arg0)
{
    return 0;
}

void
submenu_print(
              struct menu_entry * entry,
              int         x,
              int         y
              )
{
    static char msg[200];
    int i;
    msg[0] = '\0';
    STR_APPEND(msg, "%s", entry->name);
    if (entry->priv && entry->select != (void(*)(void*,int))run_in_separate_task)
    {
        int l = strlen(entry->name);
        for (i = 0; i < 14 - l; i++)
            STR_APPEND(msg, " ");
        if (entry->choices && MEM(entry->priv) <= entry->max)
        {
            STR_APPEND(msg, ": %s", entry->choices[MEM(entry->priv)]);
        }
        else if (entry->min == 0 && entry->max == 1)
        {
            STR_APPEND(msg, ": %s", MEM(entry->priv) ? "ON" : "OFF");
        }
        else
        {
            switch (entry->unit)
            {
                case UNIT_1_8_EV:
                case UNIT_x10:
                case UNIT_PERCENT_x10:
                {
                    int v = MEM(entry->priv);
                    int den = entry->unit == UNIT_1_8_EV ? 8 : 10;
                    STR_APPEND(msg, ": %s%d", v < 0 ? "-" : "", ABS(v)/den);
                    int r = (ABS(v)%den)*10/den;
                    if (r) STR_APPEND(msg, ".%d", r);
                    STR_APPEND(msg, "%s",
                               entry->unit == UNIT_1_8_EV ? " EV" :
                               entry->unit == UNIT_PERCENT_x10 ? "%%" : ""
                               );
                    break;
                }
                case UNIT_PERCENT:
                {
                    STR_APPEND(msg, ": %d%%", MEM(entry->priv));
                    break;
                }
                case UNIT_ISO:
                {
                    if (!MEM(entry->priv)) { STR_APPEND(msg, ": Auto"); }
                    else { STR_APPEND(msg, ": %d", raw2iso(MEM(entry->priv))); }
                    break;
                }
                case UNIT_HEX:
                {
                    STR_APPEND(msg, ": 0x%x", MEM(entry->priv));
                    break;
                }
                default:
                {
                    STR_APPEND(msg, ": %d", MEM(entry->priv));
                    break;
                }
            }
        }
    }
    bmp_printf(
               entry->selected ? MENU_FONT_SEL : MENU_FONT,
               x, y,
               msg
               );
    
    entry_draw_icon(entry, x, y);
}


static struct menu *
menu_find_by_name(
                  const char *        name,
                  int icon
                  )
{
    take_semaphore( menu_sem, 0 );
    
    struct menu *       menu = menus;
    
    for( ; menu ; menu = menu->next )
    {
        if( streq( menu->name, name ) )
        {
            give_semaphore( menu_sem );
            return menu;
        }
        
        // Stop just before we get to the end
        if( !menu->next )
            break;
    }
    
    // Not found; create it
    struct menu * new_menu = AllocateMemory( sizeof(*new_menu) );
    if( !new_menu )
    {
        give_semaphore( menu_sem );
        return NULL;
    }
    
    new_menu->id        = menu_id_increment++;
    new_menu->name      = name;
    new_menu->icon      = icon;
    new_menu->prev      = menu;
    new_menu->next      = NULL; // Inserting at end
    new_menu->children  = NULL;
    
    // menu points to the last entry or NULL if there are none
    if( menu )
    {
        // We are adding to the end
        menu->next      = new_menu;
        new_menu->selected  = 0;
    } else {
        // This is the first one
        menus           = new_menu;
        new_menu->selected  = 1;
    }
    
    give_semaphore( menu_sem );
    return new_menu;
}


void
menu_add(
         const char *        name,
         struct menu_entry * new_entry,
         int         count
         )
{
#if 1
    // There is nothing to display. Sounds crazy (but might result from ifdef's)
    if ( count == 0 )
        return;
    
    // Walk the menu list to find a menu
    struct menu *       menu = menu_find_by_name( name, 0);
    if( !menu )
        return;
    
    int count0 = count; // for submenus
    
    take_semaphore( menu_sem, 0 );
    
    struct menu_entry * head = menu->children;
    if( !head )
    {
        // First one -- insert it as the selected item
        head = menu->children   = new_entry;
        if (new_entry->id == 0) new_entry->id = menu_id_increment++;
        new_entry->next     = NULL;
        new_entry->prev     = NULL;
        new_entry->selected = 1;
        if (IS_SUBMENU(menu)) new_entry->essential = FOR_SUBMENU;
        new_entry++;
        count--;
    }
    
    // Find the end of the entries on the menu already
    while( head->next )
        head = head->next;
    
    int i;
    for (i = 0; i < count; i++)
    {
        if (new_entry->id == 0) new_entry->id = menu_id_increment++;
        new_entry->selected = 0;
        if (IS_SUBMENU(menu)) new_entry->essential = FOR_SUBMENU;
        new_entry->next     = head->next;
        new_entry->prev     = head;
        head->next      = new_entry;
        
        head            = new_entry;
        new_entry++;
    }
    give_semaphore( menu_sem );
    
    
    // create submenus
    
    struct menu_entry * entry = head;
    for (i = 0; i < count0; i++)
    {
        if (entry->children)
        {
            int count = 0;
            struct menu_entry * child = entry->children;
            while (!MENU_IS_EOL(child)) { count++; child++; }
            menu_find_by_name( entry->name, ICON_ML_SUBMENU);
            menu_add(entry->name, entry->children, count);
        }
        entry = entry->prev;
        if (!entry) break;
    }
    
#else
    // Maybe later...
    struct menu_entry * child = head->child;
    if( !child )
    {
        // No other child entries; add this one
        // and select it
        new_entry->highlighted  = 1;
        new_entry->prev     = NULL;
        new_entry->next     = NULL;
        head->child     = new_entry;
        return;
    }
    
    // Walk the child list to find the end
    while( child->next )
        child = child->next;
    
    // Push the new entry onto the end of the list
    new_entry->selected = 0;
    new_entry->prev     = child;
    new_entry->next     = NULL;
    child->next     = new_entry;
#endif
}

static void batsu(int x, int y, int c)
{
    int i;
    for (i = 1; i < 4; i++)
    {
        draw_line(x + 8 + i, y + 9, x + 21 + i, y + 22, c);
        draw_line(x + 21 + i, y + 9, x + 8 + i, y + 22, c);
    }
}

static void crossout(int x, int y, int color)
{
    x += 16;
    y += 16;
    int r;
    for (r = 9; r < 10; r++)
    {
        int i = r-9;
        draw_circle(x,     y, r, color);
        draw_circle(x + 1, y, r, color);
        draw_line(x + 5 + i, y - 5, x - 5 + i, y + 5, color);
    }
}

void dot(int x, int y, int color, int radius)
{
    int r;
    for (r = 0; r < radius; r++)
    {
        draw_circle(x + 16, y + 16, r, color);
        draw_circle(x + 17, y + 16, r, color);
    }
}


void maru(int x, int y, int color)
{
    dot(x, y, color, 10);
}

static void percent(int x, int y, int value)
{
    int i;
    y -= 2;
    value = value * 28 / 100;
    for (i = 0; i < 28; i++)
        draw_line(x + 2 + i, y + 25, x + 2 + i, y + 25 - i/3 - 5,
                  i <= value ? 9 : 60
                  );
}

static void playicon(int x, int y)
{
    int i;
    for (i = 5; i < 32-5; i++)
    {
        draw_line(x + 7, y + i, x + 25, y + 16, COLOR_YELLOW);
        draw_line(x + 7, y + i, x + 25, y + 16, COLOR_YELLOW);
    }
}

static void leftright_sign(int x, int y)
{
    int i;
    for (i = 5; i < 32-5; i++)
    {
        draw_line(x + 3, y + i, x + 18 + 3, y + 16, COLOR_WHITE);
        draw_line(x + 3, y + i, x + 18 + 3, y + 16, COLOR_WHITE);
        
        draw_line(x - 3, y + i, x - 18 - 3, y + 16, COLOR_WHITE);
        draw_line(x - 3, y + i, x - 18 - 3, y + 16, COLOR_WHITE);
    }
}

static int playicon_square(int x, int y, int color)
{
    bmp_draw_rect(color,x+1,y+4,38,32);
    bmp_draw_rect(color,x+2,y+5,36,30);
    int i;
    for (i = 12; i < 40-12; i++)
    {
        draw_line(x + 10, y + i, x + 30, y + 20, color);
        draw_line(x + 10, y + i, x + 30, y + 20, color);
    }
    return 40;
}

void submenu_icon(int x, int y)
{
    //~ int color = COLOR_WHITE;
    x -= 40;
    bmp_draw_rect(45, x+2, y+5, 32-3, 32-10+1);
    draw_line(x+20, y+28, x+30, y+28, COLOR_WHITE);
    int i;
    for (i = -2; i <= 2; i++)
        draw_line(x+26, y+28+i, x+30, y+28, COLOR_WHITE);
    //~ for (int r = 0; r < 2; r++)
    //~ {
    //~ draw_circle(x + 30, y + 28, r, color);
    //~ draw_circle(x + 23, y + 28, r, color);
    //~ draw_circle(x + 16, y + 28, r, color);
    //~ }
}

void submenu_only_icon(int x, int y, int value)
{
    //~ bmp_draw_rect(50, x+2, y+5, 32-3, 32-10);
    int color = value ? COLOR_GREEN1 : 45;
    int r;
    for (r = 0; r < 3; r++)
    {
        draw_circle(x + 8, y + 10, r, color);
        draw_circle(x + 8, y + 16, r, color);
        draw_circle(x + 8, y + 22, r, color);
        draw_circle(x + 9, y + 10, r, color);
        draw_circle(x + 9, y + 16, r, color);
        draw_circle(x + 9, y + 22, r, color);
    }
    
    color = value ? COLOR_WHITE : 45;
    bmp_draw_rect(color, x + 15, y + 10, 10, 1);
    bmp_draw_rect(color, x + 15, y + 16, 10, 1);
    bmp_draw_rect(color, x + 15, y + 22, 10, 1);
}

int bmp_color_scheme = 0;

void selection_bar(int x0, int y0)
{
    int w = x0 + 720 - 40 - 10;
    if (submenu_mode==1) w -= 90;
    
    extern int bmp_color_scheme;
    
    uint8_t* B = bmp_vram();
    int y;
    for (y = y0; y < y0 + 31; y++)
    {
        int x;
        for (x = x0-5; x < w; x++)
        {
            if (B[BM(x,y)] == COLOR_BLACK)
                B[BM(x,y)] = submenu_mode || bmp_color_scheme ? COLOR_LIGHTBLUE : COLOR_BLUE;
        }
    }
}

void size_icon(int x, int y, int current, int nmax)
{
    dot(x, y, COLOR_GREEN1, current * (nmax > 2 ? 9 : 7) / (nmax-1) + 3);
}

void dice_icon(int x, int y, int current, int nmax)
{
#define C(i) (current == (i) ? COLOR_GREEN1 : 50), (current == (i) ? 6 : 4)
    //~ x -= 40;
    //~ x += 16; y += 16;
    switch (nmax)
    {
        case 2:
            dot(x - 6, y + 6, C(0)+2);
            dot(x + 6, y - 6, C(1)+2);
            break;
        case 3:
            dot(x    , y - 7, C(0));
            dot(x - 7, y + 3, C(1));
            dot(x + 7, y + 3, C(2));
            break;
        case 4:
            dot(x - 6, y - 6, C(0));
            dot(x + 6, y - 6, C(1));
            dot(x - 6, y + 6, C(2));
            dot(x + 6, y + 6, C(3));
            break;
        case 5:
            dot(x,     y,     C(0));
            dot(x - 8, y - 8, C(1));
            dot(x + 8, y - 8, C(2));
            dot(x + 8, y + 8, C(3));
            dot(x - 8, y + 8, C(4));
            break;
        case 6:
            dot(x - 10, y - 8, C(0));
            dot(x     , y - 8, C(1));
            dot(x + 10, y - 8, C(2));
            dot(x - 10, y + 8, C(3));
            dot(x     , y + 8, C(4));
            dot(x + 10, y + 8, C(5));
            break;
        case 7:
            dot(x - 10, y - 10, C(0));
            dot(x     , y - 10, C(1));
            dot(x + 10, y - 10, C(2));
            dot(x - 10, y + 10, C(3));
            dot(x     , y + 10, C(4));
            dot(x + 10, y + 10, C(5));
            dot(x     , y     , C(6));
            break;
        case 8:
            dot(x - 10, y - 10, C(0));
            dot(x     , y - 10, C(1));
            dot(x + 10, y - 10, C(2));
            dot(x - 10, y + 10, C(3));
            dot(x     , y + 10, C(4));
            dot(x + 10, y + 10, C(5));
            dot(x -  5, y     , C(6));
            dot(x +  5, y     , C(7));
            break;
        case 9:
            dot(x - 10, y - 10, C(0));
            dot(x     , y - 10, C(1));
            dot(x + 10, y - 10, C(2));
            dot(x - 10, y     , C(3));
            dot(x     , y     , C(4));
            dot(x + 10, y     , C(5));
            dot(x - 10, y + 10, C(6));
            dot(x     , y + 10, C(7));
            dot(x + 10, y + 10, C(10));
            break;
        default:
            size_icon(x, y, current, nmax);
            break;
    }
#undef C
}

void color_icon(int x, int y, const char* color)
{
    if (streq(color, "Red"))
        maru(x, y, COLOR_RED);
    else if (streq(color, "Green"))
        maru(x, y, COLOR_GREEN2);
    else if (streq(color, "Blue"))
        maru(x, y, COLOR_LIGHTBLUE);
    else if (streq(color, "Cyan"))
        maru(x, y, COLOR_CYAN);
    else if (streq(color, "Magenta"))
        maru(x, y, 14);
    else if (streq(color, "Yellow"))
        maru(x, y, COLOR_YELLOW);
    else if (streq(color, "Orange"))
        maru(x, y, COLOR_ORANGE);
    else if (streq(color, "White"))
        maru(x, y, COLOR_WHITE);
    else if (streq(color, "Black"))
        maru(x, y, COLOR_WHITE);
    else if (streq(color, "Luma"))
        maru(x, y, 60);
    else if (streq(color, "RGB"))
    {
        dot(x,     y - 7, COLOR_RED, 5);
        dot(x - 7, y + 3, COLOR_GREEN2, 5);
        dot(x + 7, y + 3, COLOR_LIGHTBLUE, 5);
    }
    else if (streq(color, "ON"))
        maru(x, y, COLOR_GREEN1);
    else if (streq(color, "OFF"))
        maru(x, y, 40);
    else
    {
        dot(x,     y - 7, COLOR_CYAN, 5);
        dot(x - 7, y + 3, COLOR_RED, 5);
        dot(x + 7, y + 3, COLOR_YELLOW, 5);
    }
}

// By default, icon type is MNI_BOOL(*(int*)priv)
// To override, call menu_draw_icon from the display functions

// Icon is only drawn once for each menu item, even if this is called multiple times
// Only the first call is executed

int icon_drawn = 0;
void menu_draw_icon(int x, int y, int type, intptr_t arg)
{
    if (icon_drawn) return;
    icon_drawn = type;
    x -= 40;
    if (type >= 0) bmp_printf(FONT_LARGE, x, y, "  "); // cleanup background
    warning_msg = 0;
    switch(type)
    {
        case MNI_OFF: maru(x, y, 40); return;
        case MNI_ON: maru(x, y, COLOR_GREEN1); return;
        case MNI_DISABLE: batsu(x, y, COLOR_RED); return;
        case MNI_NEUTRAL: maru(x, y, 60); return;
        case MNI_WARNING: maru(x, y, COLOR_RED); warning_msg = (char *) arg; return;
        case MNI_AUTO: maru(x, y, 9); return;
        case MNI_PERCENT: percent(x, y, arg); return;
        case MNI_ACTION: playicon(x, y); return;
        case MNI_DICE: dice_icon(x, y, arg & 0xFFFF, arg >> 16); return;
        case MNI_SIZE: size_icon(x, y, arg & 0xFFFF, arg >> 16); return;
        case MNI_NAMED_COLOR: color_icon(x, y, (char *)arg); return;
        case MNI_SUBMENU: submenu_only_icon(x, y, arg); return;
    }
}


static int
menu_has_visible_items(struct menu_entry *  menu)
{
    while( menu )
    {
        if (/*advanced_mode ||*/ IS_ESSENTIAL(menu))
        {
            return 1;
        }
        menu = menu->next;
    }
    return 0;
}


static void
menu_display(
             struct menu_entry * menu,
             int         x,
             int         y
             )
{
    while( menu )
    {
        if (advanced_mode || IS_ESSENTIAL(menu))
        {
            // display help (should be first; if there are too many items in menu, the main text should overwrite the help, not viceversa)
            if (menu->selected && menu->help)
            {
                bmp_printf(
                           FONT(FONT_MED, 0xC, COLOR_BLACK), // red
                           10,  450, 
                           "                                                           "
                           );
                bmp_printf(
                           FONT(FONT_MED, COLOR_WHITE, COLOR_BLACK), 
                           10 /* + ((700/font_med.width) - strlen(menu->help)) * font_med.width / 2*/,  450, 
                           menu->help
                           );
            }
            
            // display icon (only the first icon is drawn)
            icon_drawn = 0;
            if (!show_only_selected || menu->selected)
            {
                if (menu->display)
                    menu->display(
                                  menu->priv,
                                  x,
                                  y,
                                  menu->selected
                                  );
                else
                    submenu_print(menu, x, y);
            }
            
            // this should be after menu->display, in order to allow it to override the icon
            if (menu->selected || !show_only_selected)
            {
                entry_draw_icon(menu, x, y);
            }
            
            // display key help
            if (menu->selected && !is_menu_active("Help") && (menu->priv || menu->select) && y + font_large.height <  425)
            {
                char msg[100] = "";
                
                // this should follow exactly the same logic as in menu_entry_select
                // todo: remove duplicate code
                
                
                // exception for action and submenu items
                if (icon_drawn == MNI_ACTION && !submenu_mode)
                {
                    STR_APPEND(msg, "SET: run action         ");
                }
                else if (menu->select == menu_open_submenu)
                {
                    STR_APPEND(msg, "SET: open submenu       ");
                }
                // exception end
                
                else if (submenu_mode == 2)
                {
                    STR_APPEND(msg, "SET: toggle edit mode   ");
                }
                else if (show_only_selected)
                {
                    STR_APPEND(msg, "SET: toggle LiveView    ");
                }
                else if (menu->edit_mode == EM_FEW_VALUES) // SET increments
                {
                    STR_APPEND(msg, "SET: change value       ");
                }
                else if (menu->edit_mode == EM_MANY_VALUES)
                {
                    STR_APPEND(msg, "SET: toggle edit mode   ");
                }
                else if (menu->edit_mode == EM_MANY_VALUES_LV)
                {
                    /*if (lv)
                     {
                     STR_APPEND(msg, "SET: toggle LiveView    ");
                     }*/
                    if (submenu_mode != 1)
                    {
                        STR_APPEND(msg, "SET: toggle edit mode   ");
                    }
                    else // increment
                    {
                        STR_APPEND(msg, "SET: change value       ");
                    }
                }
                
                
                STR_APPEND(msg, "        ", Q_BTN_NAME);
                if (submenu_mode || show_only_selected)
                {
                    STR_APPEND(msg, "L/R/Wheel : ");
                    if (icon_drawn == MNI_ACTION)
                    {
                        STR_APPEND(msg, "run action  ");
                    }
                    else
                    {
                        STR_APPEND(msg, "change value");
                    }
                    leftright_sign(690, 400);
                }
                else if (menu->children && !submenu_mode && !show_only_selected)
                {
                    STR_APPEND(msg, "%s: open submenu ", Q_BTN_NAME);
                }
                
                bmp_printf(
                           FONT(FONT_MED, 60, COLOR_BLACK), 
                           10,  425, 
                           msg
                           );
            }
            
            // if there's a warning message set, display it
            if (menu->selected && warning_msg)
            {
                bmp_printf(
                           FONT(FONT_MED, 0xC, COLOR_BLACK), // red
                           10,  450, 
                           "                                                           "
                           );
                bmp_printf(
                           FONT(FONT_MED, 0xC, COLOR_BLACK), // red
                           10,  450, 
                           warning_msg
                           );
            }
            
            // display submenu marker if this item has a submenu
            if (menu->children && !show_only_selected)
                submenu_icon(x, y);
            
            // display selection bar
            if (menu->selected)
                selection_bar(x, y);
            
            // move down for next item
            y += font_large.height-1;
            
            // stop before attempting to display things outside the screen
            if ((unsigned)y > 480 - font_large.height 
                //~ #if CONFIG_DEBUGMSG
                && !is_menu_active("VRAM")
                //~ #endif
                ) 
                return;
        }
        menu = menu->next;
    }
}

int override_zoom_buttons = 0;

static void
menus_display(
              struct menu *       menu,
              int         orig_x,
              int         y
              )
{
    int         x = orig_x;
    
    take_semaphore( menu_sem, 0 );
    
    extern int override_zoom_buttons; // from focus.c
    override_zoom_buttons = 0; // will override them only if rack focus items are selected
    
    //~ if (!show_only_selected)
    //~ bmp_printf(
    //~ FONT(FONT_MED, 55, COLOR_BLACK), // gray
    //~  10,  430, 
    //~ MENU_NAV_HELP_STRING
    //~ );
    
    bmp_fill(40, orig_x, y, 720, 42);
    bmp_fill(70, orig_x, y+42, 720, 1);
    for( ; menu ; menu = menu->next )
    {
        if (!menu_has_visible_items(menu->children))
            continue; // empty menu
        if (IS_SUBMENU(menu))
            continue;
        
        int fg = menu->selected ? COLOR_WHITE : 70;
        int bg = menu->selected ? COLOR_BLUE : 40;
        unsigned fontspec = FONT(
                                 menu->selected ? FONT_LARGE : FONT_MED,
                                 fg,
                                 bg
                                 );
        
        if (!show_only_selected)
        {
            int w = fontspec_font( fontspec )->width * 6;
            //int h = fontspec_font( fontspec )->height;
            int icon_w = 0;
            if (menu->icon)
            {
                bmp_fill(bg, x+1, y, 200, 40);
                //- if (menu->icon == ICON_ML_PLAY) icon_w = playicon_square(x,y,fg);
                //- else icon_w = bfnt_draw_char(menu->icon, x, y, fg, bg);
            }
            if (!menu->icon || menu->selected)
            {
                //- bfnt_puts(menu->name, x + icon_w, y, fg, bg);
                //~ bmp_printf( fontspec, x + icon_w + 5, y + (40 - h)/2, "%6s", menu->name );
                x += w;
            }
            x += 47;
            //~ if (menu->selected)
            //~ {
            //~ bmp_printf( FONT(FONT_LARGE,fg,40), orig_x + 700 - font_large.width * strlen(menu->name), y + 4, menu->name );
            //~ }
        }
        
        if( menu->selected )
            menu_display(
                         menu->children,
                         orig_x + 40,
                         y + 45
                         );
    }
    give_semaphore( menu_sem );
}


static void
implicit_submenu_display()
{
    struct menu * menu = get_selected_menu();
    int sos = show_only_selected;
    show_only_selected = 1;
    menu_display(
                 menu->children,
                 40,
                 45
                 );
    show_only_selected = sos;
}


static void
submenu_display(struct menu * submenu)
{
    if (!submenu) return;
    
    int count = 0;
    struct menu_entry * child = submenu->children;
    while (child) { count++; child = child->next; }
    int h = MIN((count + 4) * font_large.height, 400);
    
    int bx = 45;
    int by = (480 - h)/2 - 30;
    if (!show_only_selected)
    {
        bmp_fill(40,  bx,  by, 720-2*bx+4, 50);
        bmp_fill(COLOR_BLACK,  bx,  by + 50, 720-2*bx+4, h-50);
        bmp_draw_rect(70,  bx,  by, 720-2*bx, 50);
        bmp_draw_rect(COLOR_WHITE,  bx,  by, 720-2*bx, h);
        //- bfnt_puts(submenu->name,  bx + 15,  by + 5, COLOR_WHITE, 40);
    }
    
    menu_display(submenu->children,  bx + 50,  by + 50 + 20);
}


static void
menu_entry_select(
                  struct menu *   menu,
                  int mode // 0 = increment, 1 = decrement, 2 = Q, 3 = SET
                  )
{
    if( !menu )
        return;
    
    take_semaphore( menu_sem, 0 );
    struct menu_entry * entry = menu->children;
    
    for( ; entry ; entry = entry->next )
    {
        if( entry->selected )
            break;
    }
    give_semaphore( menu_sem );
    
    if( !entry )
        return;
    
    //~ if (entry->show_liveview)
    //~ menu_show_only_selected();
    
    if(mode == 1) // decrement
    {
        if( entry->select_reverse ) entry->select_reverse( entry->priv, -1 );
        else if (entry->select) entry->select( entry->priv, -1);
        else menu_numeric_toggle(entry->priv, -1, entry->min, entry->max);
    }
    else if (mode == 2) // Q
    {
        if ( entry->select_Q ) entry->select_Q( entry->priv, 1);
        else { submenu_mode = !submenu_mode; show_only_selected = 0; }
    }
    else if (mode == 3) // SET
    {
        if (submenu_mode == 2) submenu_mode = 0;
        else if (show_only_selected && entry->icon_type != IT_ACTION) show_only_selected = 0;
        else if (entry->edit_mode == EM_FEW_VALUES) // SET increments
        {
            if( entry->select ) entry->select( entry->priv, 1);
            else menu_numeric_toggle(entry->priv, 1, entry->min, entry->max);
        }
        else if (entry->edit_mode == EM_MANY_VALUES)
        {
            submenu_mode = (!submenu_mode)*2;
            show_only_selected = 0;
        }
        else if (entry->edit_mode == EM_MANY_VALUES_LV)
        {
            //if (lv) show_only_selected = !show_only_selected;
            if (submenu_mode != 1) submenu_mode = (!submenu_mode)*2;
            else // increment
            {
                if( entry->select ) entry->select( entry->priv, 1);
                else menu_numeric_toggle(entry->priv, 1, entry->min, entry->max);
            }
        }
    }
    else // increment
    {
        if( entry->select ) entry->select( entry->priv, 1);
        else menu_numeric_toggle(entry->priv, 1, entry->min, entry->max);
    }
    
    config_dirty = 1;
}


/** Scroll side to side in the list of menus */
static void
menu_move(
          struct menu *       menu,
          int         direction
          )
{
    //~ menu_damage = 1;
    
    if( !menu )
        return;
    
    int rc = take_semaphore( menu_sem, 1000 );
    if( rc != 0 )
        return;
    
    // Deselect the current one
    menu->selected      = 0;
    
    if( direction < 0 )
    {
        if( menu->prev )
            menu = menu->prev;
        else {
            // Go to the last one
            while( menu->next )
                menu = menu->next;
        }
    } else {
        if( menu->next )
            menu = menu->next;
        else {
            // Go to the first one
            while( menu->prev )
                menu = menu->prev;
        }
    }
    
    // Select the new one (which might be the same)
    menu->selected      = 1;
    menu_first_by_icon = menu->icon;
    give_semaphore( menu_sem );
    
    if (IS_SUBMENU(menu) || !menu_has_visible_items(menu->children))
        menu_move(menu, direction); // this menu is hidden, skip it (try again)
                                    // will fail if no menus are displayed!
}


/** Scroll up or down in the currently displayed menu */
static void
menu_entry_move(
                struct menu *       menu,
                int         direction
                )
{
    if( !menu )
        return;
    
    int rc = take_semaphore( menu_sem, 1000 );
    if( rc != 0 )
        return;
    
    if (!menu_has_visible_items(menu->children))
        return;
    
    struct menu_entry * entry = menu->children;
    
    for( ; entry ; entry = entry->next )
    {
        if( entry->selected )
            break;
    }
    
    // Nothing selected?
    if( !entry )
    {
        give_semaphore( menu_sem );
        return;
    }
    
    // Deslect the current one
    entry->selected = 0;
    
    if( direction < 0 )
    {
        // First and moving up?
        if( entry->prev )
            entry = entry->prev;
        else {
            // Go to the last one
            while( entry->next )
                entry = entry->next;
        }
    } else {
        // Last and moving down?
        if( entry->next )
            entry = entry->next;
        else {
            // Go to the first one
            while( entry->prev )
                entry = entry->prev;
        }
    }
    
    // Select the new one, which might be the same as the old one
    entry->selected = 1;
    give_semaphore( menu_sem );
    
    if (!advanced_mode && !IS_ESSENTIAL(entry))
        menu_entry_move(menu, direction); // try again, skip hidden items
                                          // warning: would block if the menu is empty
}

int zebra_should_run()
{
    return 0;
}

void 
menu_redraw_do()
{
    menu_damage = 0;
    
    if (!DISPLAY_IS_ON) return;
    if (sensor_cleaning) return;
    //- if (gui_state == GUISTATE_MENUDISP) return;
    
    int double_buffering = 0;
    
    if (menu_help_active)
    {
        //- menu_help_redraw();
        menu_damage = 0;
    }
    else
    {
        if (!lv) show_only_selected = 0;
        //~ if (MENU_MODE || lv) clrscr();
        
        //~ menu_damage = 0;
        if (double_buffering)
        {
            // draw to mirror buffer to avoid flicker
            //~ bmp_idle_copy(0); // no need, drawing is fullscreen anyway
            //- bmp_draw_to_idle(1);
        }
        
        static int prev_so = 0;
        if (show_only_selected)
        {
            bmp_fill( 0, 0, 0, 720, 480 );
            if (zebra_should_run())
            {
                //- if (prev_so) copy_zebras_from_mirror();
                //- else cropmark_clear_cache(); // will clear BVRAM mirror and reset cropmarks
            }
            //-
            /*if (hist_countdown == 0 && !should_draw_zoom_overlay())
                draw_histogram_and_waveform(); // too slow
            else
                hist_countdown--;*/
        }
        else
        {
            bmp_fill(COLOR_BLACK, 0, 0, 720, 480 );
        }
        prev_so = show_only_selected;
        
        // this part needs to know which items are selected - don't run it in the middle of selection changing
        take_semaphore(menu_redraw_sem, 0);
        
        if (!show_only_selected || !submenu_mode)
            menus_display( menus, 0, 0 ); 
        
        if (!show_only_selected && !submenu_mode)
            if (is_menu_active("Help")) menu_show_version();
        
        if (submenu_mode)
        {
            //- if (!show_only_selected) bmp_dim();
            struct menu * submenu = get_current_submenu();
            if (submenu) submenu_display(submenu);
            else implicit_submenu_display();
        }
        
        give_semaphore(menu_redraw_sem);
        
        if (show_only_selected) 
        {
            //- draw_ml_topbar(0, 1);
            //- draw_ml_bottombar(0, 1);
        }
        
        //- if (recording)
        //- bmp_make_semitransparent();
        
#if 0
        if (double_buffering)
        {
            // copy image to main buffer
            bmp_draw_to_idle(0);
            
            int screen_layout = get_screen_layout();
            if (hdmi_code == 2) // copy at a smaller scale to fit the screen
            {
                if (screen_layout == SCREENLAYOUT_16_10)
                    bmp_zoom(bmp_vram(), bmp_vram_idle(),  360,  150, /* 128 div */ 143, /* 128 div */ 169);
                else if (screen_layout == SCREENLAYOUT_16_9)
                    bmp_zoom(bmp_vram(), bmp_vram_idle(),  360,  150, /* 128 div */ 143, /* 128 div */ 185);
                else
                {
                    if (menu_upside_down) bmp_flip(bmp_vram(), bmp_vram_idle(), 0);
                    else bmp_idle_copy(1,0);
                }
            }
            else if (ext_monitor_rca)
                bmp_zoom(bmp_vram(), bmp_vram_idle(),  360,  200, /* 128 div */ 135, /* 128 div */ 135);
            else
            {
                if (menu_upside_down) bmp_flip(bmp_vram(), bmp_vram_idle());
                else bmp_idle_copy(1,0);
            }
            //~ bmp_idle_clear();
        }
#endif
        //~ update_stuff();
        
        //- lens_display_set_dirty();
    }
}

void redraw()
{
    
}


struct msg_queue * menu_redraw_queue = 0;

static void
menu_redraw_task()
{
    menu_redraw_queue = (struct msg_queue *) msg_queue_create("menu_redraw_mq", 1);
    while(1)
    {
        msleep(50);
        int msg;
        int err = msg_queue_receive(menu_redraw_queue, (struct event**)&msg, 500);
        if (err) continue;
        if (gui_menu_shown()) menu_redraw_do();
        else redraw();
    }
}
        
        
        
void
menu_redraw()
{
    if (!DISPLAY_IS_ON) return;
    //- if (ml_shutdown_requested) return;
    //- if (menu_help_active) bmp_draw_request_stop();
    if (menu_redraw_queue) msg_queue_post(menu_redraw_queue, 1);
}


static struct menu * get_selected_menu()
{
    struct menu * menu = menus;
    for( ; menu ; menu = menu->next )
        if( menu->selected )
            break;
    return menu;
}


static struct menu * get_current_submenu()
{
    if (submenu_mode == 2) return 0;
    
    struct menu * menu = menus;
    for( ; menu ; menu = menu->next )
        if( menu->selected )
            break;
    struct menu_entry * entry = menu->children;
    for( ; entry ; entry = entry->next )
        if( entry->selected )
            break;
    if (entry->children)
        return menu_find_by_name(entry->name, 0);
    
    // no submenu
    submenu_mode = 2;
    return 0;
}


static int keyrepeat = 0;
static int keyrep_countdown = 4;
static int keyrep_ack = 1;
int handle_ml_menu_keyrepeat(struct event * event)
{
    //~ if (menu_shown || arrow_keys_shortcuts_active())
    {
        switch(event->param)
        {
            case BGMT_JOY_LEFT:
            case BGMT_JOY_RIGHT:
            case BGMT_JOY_UP:
            case BGMT_JOY_DOWN:
                keyrepeat = event->param;
                break;
                
            case BGMT_JOY_ALL_UNPRESS:
                keyrepeat = 0;
                keyrep_countdown = 4;
                break;
        }
    }
    return 1;
}



void keyrepeat_ack(int button_code)
{
    if (button_code == keyrepeat) keyrep_ack = 1;
}

int
handle_ml_menu_keys(struct event * event) 
{
    if (menu_shown || arrow_keys_shortcuts_active())
        handle_ml_menu_keyrepeat(event);
    
    if (!menu_shown) return 1;
    
    // rack focus may override some menu keys
    //- if (handle_rack_focus_menu_overrides(event)==0) return 0;
    
    // the first steps may temporarily change the selected menu item - don't redraw in the middle of this
    take_semaphore(menu_redraw_sem, 0);
    
    // Find the selected menu (should be cached?)
    struct menu * menu = get_selected_menu();
    
    // Make sure we are not displaying an empty menu
    if (!menu_has_visible_items(menu->children))
    {
        menu_move(menu, -1); menu = get_selected_menu();
        menu_move(menu, 1); menu = get_selected_menu();
    }
    
    menu_entry_move(menu, -1);
    menu_entry_move(menu, 1);
    
    struct menu * help_menu = menu;
    if (submenu_mode)
    {
        help_menu = menu;
        menu = get_current_submenu();
        if (!menu) menu = help_menu; // no submenu, operate on same item
    }
    
    give_semaphore(menu_redraw_sem);
    
    int button_code = event->param;
    
    switch( button_code )
    {
        case BGMT_MENU:
            if (submenu_mode) submenu_mode = 0;
            else advanced_mode = !advanced_mode;
            show_only_selected = 0;
            menu_help_active = 0;
            break;
            
            //- need to find event code for shutter button.    
        /*case BGMT_PRESS_HALFSHUTTER: // If they press the shutter halfway
                                     //~ menu_close();
            give_semaphore(gui_sem);
            return 1;*/
            
        case BGMT_PRESS_ZOOM_IN:
            //if (lv) show_only_selected = !show_only_selected;
            /*else */ submenu_mode = (!submenu_mode)*2;
            menu_damage = 1;
            menu_help_active = 0;
            break;
            
        case BGMT_JOY_UP:
        case BGMT_WHEEL_LEFT:
            //- if (menu_help_active) { menu_help_prev_page(); break; }
            menu_entry_move( menu, -1 );
            //~ if (!submenu_mode) show_only_selected = 0;
            break;
            
        case BGMT_JOY_DOWN:
        case BGMT_WHEEL_RIGHT:
            //- if (menu_help_active) { menu_help_next_page(); break; }
            menu_entry_move( menu, 1 );
            //~ if (!submenu_mode) show_only_selected = 0;
            break;
            
        case BGMT_JOY_RIGHT:
            menu_damage = 1;
            //- if (menu_help_active) { menu_help_next_page(); break; }
            if (submenu_mode || show_only_selected) menu_entry_select( menu, 0 );
            else { menu_move( menu, 1 ); show_only_selected = 0; }
            break;
            
        case BGMT_JOY_LEFT:
            menu_damage = 1;
            //- if (menu_help_active) { menu_help_prev_page(); break; }
            if (submenu_mode || show_only_selected) menu_entry_select( menu, 1 );
            else { menu_move( menu, -1 ); show_only_selected = 0; }
            break;

        case BGMT_SET:
            if (menu_help_active) { menu_help_active = 0; /* menu_damage = 1; */ break; }
            else
            {
                menu_entry_select( menu, 3 ); // "SET" select
            }
            //~ menu_damage = 1;
            break;
            
        case BGMT_INFO:
            menu_help_active = !menu_help_active;
            show_only_selected = 0;
            //- if (menu_help_active) menu_help_go_to_selected_entry(help_menu);
            //~ menu_damage = 1;
            break;
            
        case BGMT_PLAY:
            //- if (menu_help_active) { menu_help_active = 0; /* menu_damage = 1; */ break; }
            menu_entry_select( menu, 1 ); // reverse select
                                          //~ menu_damage = 1;
            break;


        case BGMT_JUMP:
            //- if (menu_help_active) { menu_help_active = 0; /* menu_damage = 1; */ break; }
            menu_entry_select( menu, 2 ); // auto setting select
                                          //~ menu_damage = 1;
            break;
            
            
        case BGMT_JOY_UP_RIGHT:
        case BGMT_JOY_UP_LEFT:
        case BGMT_JOY_DOWN_RIGHT:
        case BGMT_JOY_DOWN_LEFT:
            break; // ignore
            
        default:
            /*DebugMsg( DM_MAGIC, 3, "%s: unknown event %08x? %08x %08x %x08",
             __func__,
             event,
             arg2,
             arg3,
             arg4
             );*/
            return 1;
    }
    
    // If we end up here, something has been changed.
    // Reset the timeout
    menu_redraw();
    keyrepeat_ack(button_code);
    hist_countdown = 3;
    return 0;
}

void
menu_init( void )
{
    menus = NULL;
    menu_sem = create_named_semaphore( "menus", 1 );
    gui_sem = create_named_semaphore( "gui", 0 );
    //- menu_redraw_sem = create_named_semaphore( "menu_r", 1);
    //- menu_find_by_name( "Expo", ICON_AE);
    //- menu_find_by_name( "LiveV", ICON_LV);
    //- menu_find_by_name( "Movie", ICON_VIDEOCAM );
    menu_find_by_name( "Shoot", ICON_PHOTOCAM );
    //~ menu_find_by_name( "Brack" );
    //- menu_find_by_name( "Focus", ICON_SHARPNESS );
    //~ menu_find_by_name( "LUA" );
    //menu_find_by_name( "Games" );
    //- menu_find_by_name( "Display", ICON_MONITOR );
    //- menu_find_by_name( "Tweaks", ICON_SMILE );
    //- menu_find_by_name( "Play", ICON_ML_PLAY );
    //- menu_find_by_name( "Power", ICON_P_SQUARE );
    //- menu_find_by_name( "Debug", ICON_HEAD_WITH_RAYS );
    //~ menu_find_by_name( "Config" );
    //- menu_find_by_name( "Config", ICON_CF );
    //- menu_find_by_name( "Help", ICON_i );
    //~ menu_find_by_name( "Boot" );
    
    /*
     bmp_printf( FONT_LARGE, 0, 40, "Yes, use this battery" );
     gui_control( ELECTRONIC_SUB_DIAL_RIGHT, 1, 0 );
     msleep( 2000 );
     gui_control( PRESS_SET_BUTTON, 1, 0 );
     msleep( 2000 );
     
     // Try to defeat the battery message
     //GUI_SetErrBattery( 1 );
     //msleep( 100 );
     //StopErrBatteryApp();
     
     msleep( 1000 );
     */
}


void
gui_stop_menu( )
{
    if (gui_menu_shown())
        give_semaphore(gui_sem);
}


int
gui_menu_shown( void )
{
    return menu_shown;
}


void piggyback_canon_menu()
{
    if (recording) return;
    if (sensor_cleaning) return;
    //- if (gui_state == GUISTATE_MENUDISP) return;
    //- NotifyBoxHide();
    //- SetGUIRequestMode(GUIMODE_ML_MENU);
    NotifyGUIEvent(6, 0); //- same thing as SetGUIRequestMode(GUIMODE_ML_MENU).
    msleep(100);
    menu_redraw();
    /*if (MENU_MODE)
    {
        msleep(100);
        menu_redraw();
        msleep(100);
        menu_redraw();
    }*/
}

void close_canon_menu()
{
    if (recording) return;
    if (sensor_cleaning) return;
    //- if (gui_state == GUISTATE_MENUDISP) return;
    //- SetGUIRequestMode(0); need to find equivilant thing ot pass to NotifyGUIEvent.
    msleep(200);
}


static void menu_open() 
{ 
    if (menu_shown) return;
    
    show_only_selected = 0;
    submenu_mode = 0;
    menu_help_active = 0;
    keyrepeat = 0;
    menu_shown = 1;
    
    piggyback_canon_menu();
    
    //- canon_gui_disable_front_buffer(0);
    //if (lv && EXT_MONITOR_CONNECTED) clrscr();
    menu_redraw();
}
static void menu_close() 
{ 
    if (!menu_shown) return;
    menu_shown = false;
    
    //- update_disp_mode_bits_from_params();
    
    //- canon_gui_enable_front_buffer(0);
    //- lens_focus_stop();
    show_only_selected = 0;
    
    if (!PLAY_MODE) { redraw(); }
    else draw_livev_for_playback();
    
    close_canon_menu();
}

int arrow_keys_shortcuts_active()
{
    return 0;
}

int should_draw_zoom_overlay()
{
    return 0;
}

void fake_simple_button()
{
    
}

int config_autosave = 0;

static void
menu_task( void* unused )
{    
    select_menu_by_icon(menu_first_by_icon);
    while(1)
    {
        int menu_or_shortcut_menu_shown = (menu_shown || arrow_keys_shortcuts_active());
        int dt = (menu_or_shortcut_menu_shown && keyrepeat) ? COERCE(100 + keyrep_countdown*5, 20, 100) : should_draw_zoom_overlay() && show_only_selected ? 2000 : 500;
        int rc = take_semaphore( gui_sem, dt );
        if( rc != 0 )
        {
            if (keyrepeat && menu_or_shortcut_menu_shown)
            {
                keyrep_countdown--;
                if (keyrep_countdown <= 0 && keyrep_ack) { keyrep_ack = 0; fake_simple_button(keyrepeat); }
                continue;
            }
            
            // We woke up after 1 second
            if( !menu_shown )
            {
                extern int config_autosave;
                if (config_autosave && config_dirty && !recording)
                {
                    //- save_config(0);
                    config_dirty = 0;
                }
                continue;
            }
            
            if ((!menu_help_active && !show_only_selected) || menu_damage) {
                menu_redraw();
            }
            
            if (sensor_cleaning && menu_shown)
                menu_close();
            
            /* if (gui_state == GUISTATE_MENUDISP && menu_shown)
             menu_close();
             */
            continue;
        }
        
        if( menu_shown )
        {
            menu_close();
            continue;
        }
        
        //if (recording && !lv) continue;
        
        // Set this flag a bit earlier in order to pause LiveView tasks.
        // Otherwise, high priority tasks such as focus peaking might delay the menu a bit.
        //~ menu_shown = true; 
        
        // ML menu needs to piggyback on Canon menu, in order to receive wheel events
        //~ piggyback_canon_menu();
        
        //~ fake_simple_button(BGMT_PICSTYLE);
        menu_open();
    }
}


int is_menu_active(char* name)
{
    if (!menu_shown) return 0;
    if (menu_help_active) return 0;
    struct menu * menu = menus;
    for( ; menu ; menu = menu->next )
        if( menu->selected )
            break;
    return !strcmp(menu->name, name);
}


static void select_menu_by_icon(int icon)
{
    take_semaphore(menu_sem, 0);
    struct menu * menu = menus;
    for( ; menu ; menu = menu->next )
    {
        if (menu->icon == icon) // found!
        {
            struct menu * menu = menus;
            for( ; menu ; menu = menu->next )
                menu->selected = menu->icon == icon;
            break;
        }
    }
    give_semaphore(menu_sem);
}

static void
menu_help_go_to_selected_entry(
                               struct menu *   menu
                               )
{
    if( !menu )
        return;
    
    take_semaphore(menu_sem, 0);
    
    struct menu_entry * entry = menu->children;
    
    for( ; entry ; entry = entry->next )
    {
        if( entry->selected )
            break;
    }
    
    //- menu_help_go_to_label(entry->name);
    
    give_semaphore(menu_sem);
}

static void menu_show_version(void)
{
    bmp_printf(FONT_MED,  10,  410,
               "5dplus version : 1.0 (Alpha)\n"
               "Mercurial changeset   : ed9956756d8d\n"
               "Built on 6/15/2012 by Coutts.");
}






void create_menu_tasks()
{
    CreateTask("menu_redraw_task", 0x1d, 0x4000, menu_redraw_task, 0);
    CreateTask("menu_task", 0x1d, 0x1000, menu_task, 0);
}

back to top