#include "mkhiblib.h" /** * Draw a menu * * @param hmenu the menu to draw * @param screen the scren to draw in */ void hl_drawMenu(h_Menu * hmenu, h_ScreenMem screen) { short j; short height_text = hmenu->font->underline + hmenu->font->upperline + (hmenu->font->underline == 0); short y = hmenu->pos_y-height_text; short height; short pos; short nb = 0; short x; short x_start; hl_fillFrame(hmenu->pos_x, hmenu->pos_y, hmenu->pos_x + hmenu->width, hmenu->pos_y + height_text * hmenu->nb_draw - 1, HGRAPHMODE_WHITE, screen); if (hmenu->level_tab != NULL) { for (j = 0; j < hmenu->nb; j++) { if (hmenu->level_tab[j].draw) { nb++; } } } else { nb = hmenu->nb; } x = hmenu->pos_x; if (hmenu->draw_scrollbar) { if (nb > hmenu->nb_draw) { height = (height_text * hmenu->nb_draw * hmenu->nb_draw) / nb - 1; } else { height = height_text * hmenu->nb_draw - 1; } pos = (height_text * hmenu->nb_draw * hmenu->top) / nb; if (height < 1) { height = 1; } hl_drawLineVert(x, hmenu->pos_y + 1, hmenu->pos_y + hmenu->nb_draw * height_text - 2, HGRAPHMODE_BLACK, screen); hl_drawLineVert(x + 3, hmenu->pos_y + 1, hmenu->pos_y + hmenu->nb_draw * height_text - 2, HGRAPHMODE_BLACK, screen); hl_drawLineHoriz(x + 1, x + 2, hmenu->pos_y, HGRAPHMODE_BLACK, screen); hl_drawLineHoriz(x + 1, x + 2, hmenu->pos_y + hmenu->nb_draw * height_text - 1, HGRAPHMODE_BLACK, screen); hl_drawLineVert(x + 1, pos + hmenu->pos_y, pos + height + hmenu->pos_y, HGRAPHMODE_BLACK, screen); hl_drawLineVert(x + 2, pos + hmenu->pos_y, pos + height + hmenu->pos_y, HGRAPHMODE_BLACK, screen); x += 7; } j = hmenu->top; nb = 0; x_start = x; while (j < hmenu->nb && nb < hmenu->nb_draw) { x = x_start; if (hmenu->level_tab != NULL && hmenu->level_tab[j].draw) { x += 6 * hmenu->level_tab[j].level; } if (hmenu->level_tab == NULL || hmenu->level_tab[j].draw) { if (hmenu->fct_draw != NULL) { hmenu->fct_draw(j, x + 5, y += height_text, hmenu, screen); } else { if (hmenu->size_item != 0) { hl_drawStr(hmenu->font, x + 5, y += height_text, hmenu->tab + j * hmenu->size_item, FALSE, FALSE, screen); } else { hl_drawStr(hmenu->font, x + 5, y += height_text, ((unsigned char * * )hmenu->tab)[j], FALSE, FALSE, screen); } } if (hmenu->no_choice == j) { hl_drawChar(hmenu->font, x, y, (hmenu->move ? 127 : 18), FALSE, FALSE, screen); } nb++; } j++; } } /** * Get the nth next item from a position * * @param pos the current position * @param n the number of item to skip * @param hmenu the menu * * @return the number of the nth next item */ short hgetnNext(short pos, short n, h_Menu * hmenu) { short last_draw = pos; if (pos == hmenu->nb - 1) return pos; do { pos++; if (hmenu->level_tab == NULL || hmenu->level_tab[pos].draw) { n--; last_draw = pos; } } while (n > 0 && pos != hmenu->nb - 1); return last_draw; } /** * Get the nth previous item from a position * * @param pos the current position * @param n the number of item to skip * @param hmenu the menu * * @return the number of the nth previous item */ short hgetnPrev(short pos, short n, h_Menu * hmenu) { short last_draw = pos; if (pos == 0) return pos; do { pos--; if (hmenu->level_tab == NULL || hmenu->level_tab[pos].draw) { n--; last_draw = pos; } } while (n > 0 && pos > 0); return last_draw; } /** * Get the next item with the same level * * @param pos the current position * @param hmenu the menu * * @return the position of the next item */ short hgetNextHierachic(short pos, h_Menu * hmenu) { short level = hmenu->level_tab[pos].level; do { pos++; } while (pos != hmenu->nb && hmenu->level_tab[pos].level > level); return pos; } /** * Draws the sublevel of an item * * @param pos the current position * @param hmenu the menu * * @return TODO doc */ short hdrawSubLevel(short pos, h_Menu * hmenu) { short level = hmenu->level_tab[pos].level; pos++; while (pos != hmenu->nb && hmenu->level_tab[pos].level > level) { hmenu->level_tab[pos].draw = 1; if (!hmenu->level_tab[pos].hide) { pos = hdrawSubLevel(pos, hmenu); } else { pos = hgetNextHierachic(pos, hmenu); } } return pos; } /** * TODO doc * * @param hmenu the menu * @param choice the current choosen item */ void hmoveItem(void * tab, short src, short dest, short size_item) { unsigned char buffer[size_item]; signed short sens=( (dest > src) ? 1 : -1 ); memcpy(buffer, tab + src * size_item, size_item); while (src != dest) { memcpy(tab + src * size_item, tab + (src + sens) * size_item, size_item); src += sens; } memcpy(tab + dest * size_item, buffer, size_item); } /** * TODO doc * * @param hmenu the menu * @param choice the current choosen item */ void hmoveItemDown(h_Menu * hmenu, short choice) { if (hmenu->move) { if (choice == 0) { choice = 1; } hmoveItem(hmenu->tab, hmenu->no_choice, choice, hmenu->size_item); if (hmenu->level_tab != NULL) { hmoveItem(hmenu->level_tab, hmenu->no_choice, choice, sizeof(h_MenuLevel)); } } hmenu->no_choice = choice; } /** * TODO doc * * @param hmenu the menu * @param choice the current choosen item */ void hmoveItemUp(h_Menu * hmenu, short choice) { if (hmenu->move) { if (choice == 0) { if (hmenu->nb <= hmenu->nb_draw) { hmenu->top = 0; } else { hmenu->top = hmenu->nb - hmenu->nb_draw; } choice = hmenu->nb - 1; } hmoveItem(hmenu->tab, hmenu->no_choice, choice, hmenu->size_item); if (hmenu->level_tab != NULL) { hmoveItem(hmenu->level_tab, hmenu->no_choice, choice, sizeof(h_MenuLevel)); } } hmenu->no_choice = choice; } /** * Go to the bottom * * @param hmenu the menu */ void hl_goMenuBottom(h_Menu * hmenu) { short choice = hgetnPrev(hmenu->nb, 1, hmenu); //get last hmenu->top = hgetnPrev(hmenu->nb, hmenu->nb_draw, hmenu); //back of one page hmoveItemDown(hmenu, choice); } /** * Go one page down * * @param hmenu the menu */ void hl_goMenuPageDown(h_Menu * hmenu) { hmenu->top = hgetnNext(hmenu->top, hmenu->nb_draw, hmenu); //go one page down from top short choice = hgetnNext(hmenu->no_choice, hmenu->nb_draw, hmenu); //go one page down from choice short no_temp = hgetnPrev(hmenu->nb, hmenu->nb_draw, hmenu); //go one page back from end if (no_temp < hmenu->top) { //overflow hmenu->top = no_temp; } hmoveItemDown(hmenu, choice); } /** * Go to the next shown item * * @param hmenu the menu */ void hl_goMenuDown(h_Menu * hmenu) { short choice = hgetnNext(hmenu->no_choice, 1, hmenu); //go one down from no_choice if (choice == hmenu->no_choice) { //we are at the end choice = hgetnNext(-1,1,hmenu); //get the first hmenu->top = choice; } else { short no_temp = hgetnNext(choice, 1, hmenu); //get the next from choice no_temp = hgetnPrev(no_temp, hmenu->nb_draw - 1, hmenu); //go back one page from no_temp : search the top if (no_temp > hmenu->top) {//overflow hmenu->top = no_temp; } no_temp = hgetnPrev(hmenu->nb, 1, hmenu); //maximum top if (no_temp < hmenu->top) {//overflow hmenu->top = no_temp; } } hmoveItemDown(hmenu, choice); } /** * Go to the top * * @param hmenu the menu */ void hl_goMenuTop(h_Menu * hmenu) { hmenu->top = hgetnNext(-1, 1, hmenu); hmenu->no_choice = hmenu->top; } /** * Go one page up * * @param hmenu the menu */ void hl_goMenuPageUp(h_Menu * hmenu) { hmenu->top = hgetnPrev(hmenu->top, hmenu->nb_draw, hmenu); //get one page back from top short choice = hgetnPrev(hmenu->no_choice, hmenu->nb_draw, hmenu); //get one page back from choice hmoveItemUp(hmenu, choice); } /** * Go to the previous shown item * * @param hmenu the menu */ void hl_goMenuUp(h_Menu * hmenu) { short choice = hgetnPrev(hmenu->no_choice, 1, hmenu); //go back one from no_choice if (choice == hmenu->no_choice) { //we are at the first choice = hgetnPrev(hmenu->nb, 1, hmenu); //go to the end hmenu->top = hgetnPrev(hmenu->nb, hmenu->nb_draw, hmenu); //go back one page from end } else { if (choice <= hmenu->top) { //overflow hmenu->top = hgetnPrev(hmenu->top, 1, hmenu); //go back one from top } } hmoveItemUp(hmenu, choice); } /** * Draws the sublevels of the active item * * @param hmenu the menu */ void hl_goSubMenu(h_Menu * hmenu) { hmenu->level_tab[hmenu->no_choice].hide = 0; //hide the item hdrawSubLevel(hmenu->no_choice, hmenu); } /** * Hide the item and its siblings and go to its parent * * @param hmenu the menu */ void hl_goUpperMenu(h_Menu * hmenu) { hmenu->level_tab[hmenu->no_choice].hide = 1; //hide the item short no_temp = hmenu->no_choice + 1; //go down and don't draw any item with a bigger level while (no_temp < hmenu->nb && hmenu->level_tab[hmenu->no_choice].level < hmenu->level_tab[no_temp].level) { hmenu->level_tab[no_temp++].draw=0; //hide the item } //calcul of the last top no_temp = hgetnPrev(hmenu->nb, hmenu->nb_draw, hmenu); if (no_temp < hmenu->top) { hmenu->top = no_temp; } }