#include "mmconf.h"
#include "mmui_context.h"
#include "freedesktop_cats.h"
+#include "mmcustom_cats.h"
#define CHANGED_NOTHING (0)
#define CHANGED_CATEGORY (1<<0) /* changed to different category */
#define CHANGED_EVERYTHING (1<<4) /* redraw it all! */
unsigned int render_mask = CHANGED_EVERYTHING;
+SDL_Thread *g_icon_thread = NULL;
+unsigned char g_icon_thread_stop = 0; /* if !0 means thread should stop and maim app may block until it goes back to 0.. */
+unsigned char g_icon_thread_busy = 0; /* if !0 means thread is running right now */
+
#define MIMETYPE_EXE "/usr/bin/file" /* check for file type prior to invocation */
/* SDL
mm_appref_t *ui_selected = NULL;
unsigned char ui_category = 0; // current category
unsigned char ui_catshift = 0; // how many cats are offscreen to the left
+ui_viewmode_e ui_viewmode = uiv_list; // default to traditional icon view; why or why is viewstate not per-viewmode :/
ui_context_t ui_display_context; // display paramaters: see mmui_context.h
unsigned char ui_detail_hidden = 0; // if >0, detail panel is hidden
// FUTURE: If multiple panels can be shown/hidden, convert ui_detail_hidden to a bitmask
-static SDL_Surface *ui_scale_image ( SDL_Surface *s, unsigned int maxwidth, int maxheight ); // height -1 means ignore
+SDL_Surface *ui_scale_image ( SDL_Surface *s, unsigned int maxwidth, int maxheight ); // height -1 means ignore
static int ui_selected_index ( void );
+static void ui_start_defered_icon_thread ( void );
+static void ui_stop_defered_icon_thread ( void );
unsigned char ui_setup ( void ) {
#endif
// key repeat
- SDL_EnableKeyRepeat ( 500, 150 );
+ SDL_EnableKeyRepeat ( 500, 125 /* 150 */ );
// images
//IMG_Init ( IMG_INIT_JPG | IMG_INIT_PNG );
{ IMG_HOURGLASS, "graphics.IMG_HOURGLASS", },
{ IMG_FOLDER, "graphics.IMG_FOLDER", },
{ IMG_EXECBIN, "graphics.IMG_EXECBIN", },
+ { IMG_SUBCATFOLDER, "graphics.IMG_SUBCATFOLDER", "graphics.IMG_FOLDER", },
+ { IMG_DOTDOTFOLDER, "graphics.IMG_DOTDOTFOLDER", "graphics.IMG_FOLDER", },
{ IMG_MAX, NULL },
+ { IMG_LIST_ALPHAMASK, NULL }, // generated
+ { IMG_LIST_ALPHAMASK_W, NULL }, // generated
};
unsigned char ui_imagecache ( char *basepath ) {
unsigned int i;
char fullpath [ PATH_MAX ];
+ unsigned char try;
// loaded
exit ( -1 );
}
- char *filename = pnd_conf_get_as_char ( g_conf, g_imagecache [ i ].confname );
+ for ( try = 0; try < 2; try++ ) {
- if ( ! filename ) {
- pnd_log ( pndn_error, "ERROR: Missing filename in conf for key: %s\n", g_imagecache [ i ].confname );
- return ( 0 );
- }
+ char *filename;
- if ( filename [ 0 ] == '/' ) {
- strncpy ( fullpath, filename, PATH_MAX );
- } else {
- sprintf ( fullpath, "%s/%s", basepath, filename );
- }
+ if ( try == 0 ) {
+ filename = pnd_conf_get_as_char ( g_conf, g_imagecache [ i ].confname );
+ } else {
+ if ( g_imagecache [ i ].alt_confname ) {
+ filename = pnd_conf_get_as_char ( g_conf, g_imagecache [ i ].alt_confname );
+ } else {
+ return ( 0 );
+ }
+ }
- if ( ! ( g_imagecache [ i ].i = IMG_Load ( fullpath ) ) ) {
- pnd_log ( pndn_error, "ERROR: Couldn't load static cache image: %s\n", fullpath );
- return ( 0 );
- }
+ if ( ! filename ) {
+ pnd_log ( pndn_error, "ERROR: (Try %u) Missing filename in conf for key: %s\n", try + 1, g_imagecache [ i ].confname );
+ if ( try == 0 ) { continue; } else { return ( 0 ); }
+ }
+
+ if ( filename [ 0 ] == '/' ) {
+ strncpy ( fullpath, filename, PATH_MAX );
+ } else {
+ sprintf ( fullpath, "%s/%s", basepath, filename );
+ }
+
+ if ( ( g_imagecache [ i ].i = IMG_Load ( fullpath ) ) ) {
+ break; // no retry needed
+ } else {
+ pnd_log ( pndn_error, "ERROR: (Try %u) Couldn't load static cache image: %s\n", try + 1, fullpath );
+ if ( try == 0 ) { continue; } else { return ( 0 ); }
+ }
+
+ } // try twice
} // for
// generated
+ //
+
//g_imagecache [ IMG_SELECTED_ALPHAMASK ].i = SDL_CreateRGBSurface ( SDL_SWSURFACE, 60, 60, 32, 0xFF0000, 0x00FF00, 0xFF, 0xFF000000 );
//boxRGBA ( g_imagecache [ IMG_SELECTED_ALPHAMASK ].i, 0, 0, 60, 60, 100, 100, 100, 250 );
+ SDL_Surface *p = g_imagecache [ IMG_SELECTED_ALPHAMASK ].i;
+ g_imagecache [ IMG_LIST_ALPHAMASK ].i = SDL_ConvertSurface ( p, p -> format, p -> flags );
+ g_imagecache [ IMG_LIST_ALPHAMASK_W ].i = SDL_ConvertSurface ( p, p -> format, p -> flags );
+
+ g_imagecache [ IMG_LIST_ALPHAMASK ].i =
+ ui_scale_image ( g_imagecache [ IMG_LIST_ALPHAMASK ].i,
+ pnd_conf_get_as_int ( g_conf, "grid.col_max" ) * pnd_conf_get_as_int ( g_conf, "grid.cell_width" ) , -1 );
+
+ g_imagecache [ IMG_LIST_ALPHAMASK_W ].i =
+ ui_scale_image ( g_imagecache [ IMG_LIST_ALPHAMASK_W ].i,
+ pnd_conf_get_as_int ( g_conf, "grid.col_max_w" ) * pnd_conf_get_as_int ( g_conf, "grid.cell_width_w" ) , -1 );
+
// post processing
//
// render everything
//
unsigned int icon_rows;
+ unsigned int icon_visible_rows = 0; // list view, max number of visible rows
#define MAXRECTS 200
SDL_Rect rects [ MAXRECTS ], src;
ui_context_t *c = &ui_display_context; // for convenience and shorthand
- // how many total rows do we need?
- if ( g_categorycount ) {
- icon_rows = g_categories [ ui_category ] -> refcount / c -> col_max;
- if ( g_categories [ ui_category ] -> refcount % c -> col_max > 0 ) {
- icon_rows++;
- }
- } else {
- icon_rows = 0;
+ // on demand icon loading
+ static int load_visible = -1;
+ if ( load_visible == -1 ) {
+ load_visible = pnd_conf_get_as_int_d ( g_conf, "minimenu.load_visible_icons", 0 );
}
#if 1
// if no selected app yet, select the first one
if ( ! ui_selected && pnd_conf_get_as_int_d ( g_conf, "minimenu.start_selected", 0 ) ) {
+
+ // pick first visible app
ui_selected = g_categories [ ui_category ] -> refs;
+
+ // change.. so we pick first visible if option is set .. but now we also try to restore
+ // selection to the last app selected in previous session (if there is one.)
+ char *previous_unique_id = pnd_conf_get_as_char ( g_conf, "minimenu.last_known_app_uid" );
+
+ if ( previous_unique_id ) {
+
+ // 1) we should already be in the right category, since its set in ui_post_scan to minimenu.last_known_catname
+ // 2) so we just pick the app in question..
+ mm_appref_t *previter = g_categories [ ui_category ] -> refs;
+ while ( previter ) {
+ if ( strcmp ( previter -> ref -> unique_id, previous_unique_id ) == 0 ) {
+ break;
+ }
+ previter = previter -> next;
+ }
+
+ if ( previter ) {
+ ui_selected = previter;
+ }
+
+ } // last known app?
+
}
#endif
+ // how many total rows do we need?
+ if ( g_categorycount ) {
+
+ if ( ui_viewmode == uiv_list ) {
+ // in list view, dimension of grid area is ..
+ // grid height == cell-height * row-max
+ // font height == display_context -> text_height
+ // padding == icon_offset_y
+ // max visible --> row-max == grid height / ( font-height + padding )
+
+ icon_rows = g_categories [ ui_category ] -> refcount; // one app per row
+ icon_visible_rows = ( c -> cell_height * c -> row_max ) / ( c -> text_height + c -> icon_offset_y );
+
+ } else {
+
+ icon_rows = g_categories [ ui_category ] -> refcount / c -> col_max;
+ if ( g_categories [ ui_category ] -> refcount % c -> col_max > 0 ) {
+ icon_rows++;
+ }
+
+ }
+
+ } else {
+ icon_rows = 0;
+ icon_visible_rows = 0;
+ }
+
// reset touchscreen regions
if ( render_jobs_b ) {
ui_register_reset();
autoscrolled = 0;
int index = ui_selected_index();
- int topleft = c -> col_max * ui_rows_scrolled_down;
- int botright = ( c -> col_max * ( ui_rows_scrolled_down + c -> row_max ) - 1 );
-
- if ( index < topleft ) {
- ui_rows_scrolled_down -= pnd_conf_get_as_int_d ( g_conf, "grid.scroll_increment", 1 );
- render_jobs_b |= R_ALL;
- autoscrolled = 1;
- } else if ( index > botright ) {
- ui_rows_scrolled_down += pnd_conf_get_as_int_d ( g_conf, "grid.scroll_increment", 1 );
- render_jobs_b |= R_ALL;
- autoscrolled = 1;
- }
+
+ if ( ui_viewmode == uiv_list ) {
+
+ if ( index >= ui_rows_scrolled_down + icon_visible_rows ) {
+ ui_rows_scrolled_down += 1;
+ autoscrolled = 1;
+ render_jobs_b |= R_ALL;
+ } else if ( index < ui_rows_scrolled_down ) {
+ ui_rows_scrolled_down -= 1;
+ autoscrolled = 1;
+ render_jobs_b |= R_ALL;
+ }
+
+ } else {
+ // icons
+
+ int topleft = c -> col_max * ui_rows_scrolled_down;
+ int botright = ( c -> col_max * ( ui_rows_scrolled_down + c -> row_max ) - 1 );
+
+ if ( index < topleft ) {
+ ui_rows_scrolled_down -= pnd_conf_get_as_int_d ( g_conf, "grid.scroll_increment", 1 );
+ render_jobs_b |= R_ALL;
+ autoscrolled = 1;
+ } else if ( index > botright ) {
+ ui_rows_scrolled_down += pnd_conf_get_as_int_d ( g_conf, "grid.scroll_increment", 1 );
+ render_jobs_b |= R_ALL;
+ autoscrolled = 1;
+ }
+
+ } // viewmode
} // while autoscrolling
ui_rows_scrolled_down = icon_rows;
}
- } // ensire visible
+ } // ensure visible
// render background
if ( render_jobs_b & R_BG ) {
}
}
+ // any apps to render at all?
if ( g_categories [ ui_category ] -> refs ) {
- appiter = g_categories [ ui_category ] -> refs;
- row = 0;
- displayrow = 0;
+ // render grid differently based on view mode..
+ //
+ if ( ui_viewmode == uiv_list ) {
- // until we run out of apps, or run out of space
- while ( appiter != NULL ) {
+ appiter = g_categories [ ui_category ] -> refs;
+ row = 0; // row under consideration (ie: could be scrolled off)
+ displayrow = 0; // rows displayed
- for ( col = 0; col < c -> col_max && appiter != NULL; col++ ) {
+ while ( appiter != NULL ) {
// do we even need to render it? or are we suppressing it due to rows scrolled off the top?
if ( row >= ui_rows_scrolled_down ) {
- // selected? show hilights
+ // background hilight
+ SDL_Surface *hilight = ui_detail_hidden ? g_imagecache [ IMG_LIST_ALPHAMASK_W ].i : g_imagecache [ IMG_LIST_ALPHAMASK ].i;
if ( appiter == ui_selected ) {
- SDL_Surface *s = g_imagecache [ IMG_SELECTED_ALPHAMASK ].i;
- // icon
- //dest -> x = grid_offset_x + ( col * cell_width ) + icon_offset_x + ( ( icon_max_width - s -> w ) / 2 );
- dest -> x = c -> grid_offset_x + ( col * c -> cell_width ) + c -> icon_offset_x + c -> sel_icon_offset_x;
- //dest -> y = grid_offset_y + ( displayrow * cell_height ) + icon_offset_y + ( ( icon_max_height - s -> h ) / 2 );
- dest -> y = c -> grid_offset_y + ( displayrow * c -> cell_height ) + c -> icon_offset_y + c -> sel_icon_offset_y;
- SDL_BlitSurface ( s, NULL /* all */, sdl_realscreen, dest );
- dest++;
- // text
- dest -> x = c -> grid_offset_x + ( col * c -> cell_width ) + c -> text_clip_x;
- dest -> y = c -> grid_offset_y + ( displayrow * c -> cell_height ) + c -> text_hilite_offset_y;
- SDL_BlitSurface ( g_imagecache [ IMG_SELECTED_HILITE ].i, NULL /* all */, sdl_realscreen, dest );
+ src.x = 0;
+ src.y = 0;
+ src.w = hilight -> w;
+ src.h = c -> text_height + c -> icon_offset_y;
+ dest -> x = c -> grid_offset_x + c -> text_clip_x;
+ dest -> y = c -> grid_offset_y + ( displayrow * ( c -> text_height + c -> icon_offset_y ) ) - ( c -> icon_offset_y / 2 );
+ SDL_BlitSurface ( hilight, &src, sdl_realscreen, dest );
dest++;
- } // selected?
+ }
// show icon
mm_cache_t *ic = cache_query_icon ( appiter -> ref -> unique_id );
- SDL_Surface *iconsurface;
if ( ic ) {
- iconsurface = ic -> i;
- } else {
- //pnd_log ( pndn_warning, "WARNING: TBD: Need Missin-icon icon for '%s'\n", IFNULL(appiter -> ref -> title_en,"No Name") );
-
- // no icon override; was this a pnd-file (show the unknown icon then), or was this generated from
- // filesystem (file or directory icon)
- if ( appiter -> ref -> object_flags & PND_DISCO_GENERATED ) {
- if ( appiter -> ref -> object_type == pnd_object_type_directory ) {
- iconsurface = g_imagecache [ IMG_FOLDER ].i;
- } else {
- iconsurface = g_imagecache [ IMG_EXECBIN ].i;
- }
- } else {
- iconsurface = g_imagecache [ IMG_ICON_MISSING ].i;
- }
-
+ dest -> x = c -> grid_offset_x + c -> text_clip_x;
+ dest -> y = c -> grid_offset_y + ( displayrow * ( c -> text_height + c -> icon_offset_y ) ) - ( c -> icon_offset_y / 2 );
+ SDL_BlitSurface ( ic -> itiny, NULL, sdl_realscreen, dest );
}
- // got an icon I hope?
- if ( iconsurface ) {
- //pnd_log ( pndn_debug, "Got an icon for '%s'\n", IFNULL(appiter -> ref -> title_en,"No Name") );
-
- src.x = 0;
- src.y = 0;
- src.w = 60;
- src.h = 60;
- dest -> x = c -> grid_offset_x + ( col * c -> cell_width ) + c -> icon_offset_x + (( c -> icon_max_width - iconsurface -> w ) / 2);
- dest -> y = c -> grid_offset_y + ( displayrow * c -> cell_height ) + c -> icon_offset_y + (( c -> icon_max_height - iconsurface -> h ) / 2);
-
- SDL_BlitSurface ( iconsurface, &src, sdl_realscreen, dest );
-
- // store touch info
- ui_register_app ( appiter, dest -> x, dest -> y, src.w, src.h );
-
- dest++;
-
- }
-
- // show text
+ // show title text
if ( appiter -> ref -> title_en ) {
SDL_Surface *rtext;
rtext = TTF_RenderText_Blended ( g_grid_font, appiter -> ref -> title_en, c -> fontcolor );
src.x = 0;
src.y = 0;
- src.w = c -> text_width < rtext -> w ? c -> text_width : rtext -> w;
+ src.w = hilight -> w; //c -> text_width < rtext -> w ? c -> text_width : rtext -> w;
src.h = rtext -> h;
- if ( rtext -> w > c -> text_width ) {
- dest -> x = c -> grid_offset_x + ( col * c -> cell_width ) + c -> text_clip_x;
- } else {
- dest -> x = c -> grid_offset_x + ( col * c -> cell_width ) + c -> text_offset_x - ( rtext -> w / 2 );
+
+ dest -> x = c -> grid_offset_x + c -> text_clip_x;
+ dest -> x += 20; // so all title-text line up, regardless of icon presence
+#if 0
+ if ( ic ) {
+ dest -> x += 20; //((SDL_Surface*)ic -> i) -> w;
}
- dest -> y = c -> grid_offset_y + ( displayrow * c -> cell_height ) + c -> text_offset_y;
+#endif
+
+ dest -> y = c -> grid_offset_y + ( displayrow * ( c -> text_height + c -> icon_offset_y ) );
SDL_BlitSurface ( rtext, &src, sdl_realscreen, dest );
SDL_FreeSurface ( rtext );
dest++;
}
- } // display now? or scrolled away..
+ } // visible or scrolled?
+
+ if ( row >= ui_rows_scrolled_down ) {
+ displayrow++;
+ }
+
+ // are we done displaying rows?
+ if ( displayrow >= icon_visible_rows ) {
+ break;
+ }
- // next
appiter = appiter -> next;
+ row++;
- } // for column 1...X
+ } // while
- if ( row >= ui_rows_scrolled_down ) {
- displayrow++;
- }
+ } else {
- row ++;
+ appiter = g_categories [ ui_category ] -> refs;
+ row = 0;
+ displayrow = 0;
+
+ // until we run out of apps, or run out of space
+ while ( appiter != NULL ) {
+
+ for ( col = 0; col < c -> col_max && appiter != NULL; col++ ) {
+
+ // do we even need to render it? or are we suppressing it due to rows scrolled off the top?
+ if ( row >= ui_rows_scrolled_down ) {
+
+ // selected? show hilights
+ if ( appiter == ui_selected ) {
+ SDL_Surface *s = g_imagecache [ IMG_SELECTED_ALPHAMASK ].i;
+ // icon
+ //dest -> x = grid_offset_x + ( col * cell_width ) + icon_offset_x + ( ( icon_max_width - s -> w ) / 2 );
+ dest -> x = c -> grid_offset_x + ( col * c -> cell_width ) + c -> icon_offset_x + c -> sel_icon_offset_x;
+ //dest -> y = grid_offset_y + ( displayrow * cell_height ) + icon_offset_y + ( ( icon_max_height - s -> h ) / 2 );
+ dest -> y = c -> grid_offset_y + ( displayrow * c -> cell_height ) + c -> icon_offset_y + c -> sel_icon_offset_y;
+ SDL_BlitSurface ( s, NULL /* all */, sdl_realscreen, dest );
+ dest++;
+ // text
+ dest -> x = c -> grid_offset_x + ( col * c -> cell_width ) + c -> text_clip_x;
+ dest -> y = c -> grid_offset_y + ( displayrow * c -> cell_height ) + c -> text_hilite_offset_y;
+ SDL_BlitSurface ( g_imagecache [ IMG_SELECTED_HILITE ].i, NULL /* all */, sdl_realscreen, dest );
+ dest++;
+ } // selected?
+
+ // show icon
+ mm_cache_t *ic = cache_query_icon ( appiter -> ref -> unique_id );
+ SDL_Surface *iconsurface;
+
+ // if icon not in cache, and its a pnd-file source, perhaps try to load it right now..
+ if ( ( ! ic ) &&
+ ( load_visible ) &&
+ ( ! ( appiter -> ref -> object_flags & PND_DISCO_GENERATED ) )
+ )
+ {
+ // try to load any icons that..
+ // - are not yet loaded
+ // - did not fail a previous load attempt
+ // this way user can upfront load all icons, or defer all icons, or even defer all icons
+ // and still try to load visible ones 'just before needed'; so not at mmenu load time, but
+ // as needed (only the ones needed.)
+
+ if ( ( appiter -> ref -> pnd_icon_pos ) ||
+ ( appiter -> ref -> icon && appiter -> ref -> object_flags & PND_DISCO_LIBPND_DD )
+ )
+ {
+
+ // try to cache it?
+ if ( ! cache_icon ( appiter -> ref, ui_display_context.icon_max_width, ui_display_context.icon_max_width ) ) {
+ // erm..
+ }
- // are we done displaying rows?
- if ( displayrow >= c -> row_max ) {
- break;
- }
+ // avoid churn
+ appiter -> ref -> pnd_icon_pos = 0;
+ if ( appiter -> ref -> icon ) {
+ free ( appiter -> ref -> icon );
+ appiter -> ref -> icon = NULL;
+ }
+
+ // pick up as if nothing happened..
+ ic = cache_query_icon ( appiter -> ref -> unique_id );
- } // while
+ }
+
+ } // load icon during rendering?
+
+ if ( ic ) {
+ iconsurface = ic -> i;
+ } else {
+ //pnd_log ( pndn_warning, "WARNING: TBD: Need Missin-icon icon for '%s'\n", IFNULL(appiter -> ref -> title_en,"No Name") );
+
+ // no icon override; was this a pnd-file (show the unknown icon then), or was this generated from
+ // filesystem (file or directory icon)
+ if ( appiter -> ref -> object_flags & PND_DISCO_GENERATED ) {
+ if ( appiter -> ref -> object_type == pnd_object_type_directory ) {
+
+ // is this a subcat, a .., or a filesystem folder?
+ //iconsurface = g_imagecache [ IMG_FOLDER ].i;
+ if ( g_categories [ ui_category ] -> fspath ) {
+ iconsurface = g_imagecache [ IMG_FOLDER ].i;
+ } else if ( strcmp ( appiter -> ref -> title_en, ".." ) == 0 ) {
+ iconsurface = g_imagecache [ IMG_DOTDOTFOLDER ].i;
+ } else {
+ iconsurface = g_imagecache [ IMG_SUBCATFOLDER ].i;
+ }
+
+ } else {
+ iconsurface = g_imagecache [ IMG_EXECBIN ].i;
+ }
+ } else {
+ iconsurface = g_imagecache [ IMG_ICON_MISSING ].i;
+ }
+
+ }
+
+ // got an icon I hope?
+ if ( iconsurface ) {
+ //pnd_log ( pndn_debug, "Got an icon for '%s'\n", IFNULL(appiter -> ref -> title_en,"No Name") );
+
+ src.x = 0;
+ src.y = 0;
+ src.w = 60;
+ src.h = 60;
+ dest -> x = c -> grid_offset_x + ( col * c -> cell_width ) + c -> icon_offset_x + (( c -> icon_max_width - iconsurface -> w ) / 2);
+ dest -> y = c -> grid_offset_y + ( displayrow * c -> cell_height ) + c -> icon_offset_y + (( c -> icon_max_height - iconsurface -> h ) / 2);
+
+ SDL_BlitSurface ( iconsurface, &src, sdl_realscreen, dest );
+
+ // store touch info
+ ui_register_app ( appiter, dest -> x, dest -> y, src.w, src.h );
+
+ dest++;
+
+ }
+
+ // show text
+ if ( appiter -> ref -> title_en ) {
+ SDL_Surface *rtext;
+ rtext = TTF_RenderText_Blended ( g_grid_font, appiter -> ref -> title_en, c -> fontcolor );
+ src.x = 0;
+ src.y = 0;
+ src.w = c -> text_width < rtext -> w ? c -> text_width : rtext -> w;
+ src.h = rtext -> h;
+ if ( rtext -> w > c -> text_width ) {
+ dest -> x = c -> grid_offset_x + ( col * c -> cell_width ) + c -> text_clip_x;
+ } else {
+ dest -> x = c -> grid_offset_x + ( col * c -> cell_width ) + c -> text_offset_x - ( rtext -> w / 2 );
+ }
+ dest -> y = c -> grid_offset_y + ( displayrow * c -> cell_height ) + c -> text_offset_y;
+ SDL_BlitSurface ( rtext, &src, sdl_realscreen, dest );
+ SDL_FreeSurface ( rtext );
+ dest++;
+ }
+
+ } // display now? or scrolled away..
+
+ // next
+ appiter = appiter -> next;
+
+ } // for column 1...X
+
+ if ( row >= ui_rows_scrolled_down ) {
+ displayrow++;
+ }
+
+ row ++;
+
+ // are we done displaying rows?
+ if ( displayrow >= c -> row_max ) {
+ break;
+ }
+
+ } // while
+
+ } // icon view
} else {
// no apps to render?
"Reveal hidden category",
"Shutdown Pandora",
"Configure Minimenu",
+ "Manage custom app categories",
"Rescan for applications",
"Cache previews to SD now",
"Run a terminal/console",
"Select a Minimenu skin",
"About Minimenu"
};
- int sel = ui_modal_single_menu ( opts, 10, "Minimenu", "Enter to select; other to return." );
+ int sel = ui_modal_single_menu ( opts, 11, "Minimenu", "Enter to select; other to return." );
char buffer [ 100 ];
if ( sel == 0 ) {
// do nothing
ui_revealscreen();
} else if ( sel == 1 ) {
+ // store conf on exit, so that last app/cat can be cached.. for ED :)
+ conf_write ( g_conf, conf_determine_location ( g_conf ) );
// shutdown
sprintf ( buffer, "sudo poweroff" );
system ( buffer );
// configure mm
unsigned char restart = conf_run_menu ( NULL );
conf_write ( g_conf, conf_determine_location ( g_conf ) );
+ conf_write ( g_conf, CONF_PREF_TEMPPATH );
if ( restart ) {
emit_and_quit ( MM_RESTART );
}
} else if ( sel == 3 ) {
+ // manage custom categories
+ ui_manage_categories();
+ } else if ( sel == 4 ) {
// rescan apps
pnd_log ( pndn_debug, "Freeing up applications\n" );
applications_free();
pnd_log ( pndn_debug, "Rescanning applications\n" );
applications_scan();
- } else if ( sel == 4 ) {
+ } else if ( sel == 5 ) {
// cache preview to SD now
extern pnd_box_handle g_active_apps;
pnd_box_handle h = g_active_apps;
iter = pnd_box_get_next ( iter );
} // while
- } else if ( sel == 5 ) {
+ } else if ( sel == 6 ) {
// run terminal
char *argv[5];
argv [ 0 ] = pnd_conf_get_as_char ( g_conf, "utility.terminal" );
ui_forkexec ( argv );
}
- } else if ( sel == 6 ) {
+ } else if ( sel == 7 ) {
char buffer [ PATH_MAX ];
sprintf ( buffer, "%s %s\n", MM_RUN, "/usr/pandora/scripts/op_switchgui.sh" );
emit_and_quit ( buffer );
- } else if ( sel == 7 ) {
- emit_and_quit ( MM_QUIT );
} else if ( sel == 8 ) {
+ emit_and_quit ( MM_QUIT );
+ } else if ( sel == 9 ) {
// select skin
if ( ui_pick_skin() ) {
emit_and_quit ( MM_RESTART );
}
- } else if ( sel == 9 ) {
+ } else if ( sel == 10 ) {
// about
char buffer [ PATH_MAX ];
sprintf ( buffer, "%s/about.txt", g_skinpath );
void ui_push_left ( unsigned char forcecoil ) {
+ if ( ui_viewmode == uiv_list ) {
+ ui_context_t *c = &ui_display_context;
+ int i;
+ int imax = ( c -> cell_height * c -> row_max ) / ( c -> text_height + c -> icon_offset_y ); // visible rows
+ for ( i = 0; i < imax; i++ ) {
+ ui_push_up();
+ }
+ return;
+ }
+
if ( ! ui_selected ) {
ui_push_right ( 0 );
return;
void ui_push_right ( unsigned char forcecoil ) {
+ if ( ui_viewmode == uiv_list ) {
+ ui_context_t *c = &ui_display_context;
+ int i;
+ int imax = ( c -> cell_height * c -> row_max ) / ( c -> text_height + c -> icon_offset_y ); // visible rows
+ for ( i = 0; i < imax; i++ ) {
+ ui_push_down();
+ }
+ return;
+ }
+
if ( ui_selected ) {
// what column we in?
}
void ui_push_up ( void ) {
+
unsigned char col_max = ui_display_context.col_max;
+ // not selected? well, no where to go..
if ( ! ui_selected ) {
return;
}
+ if ( ui_viewmode == uiv_list ) {
+
+ if ( g_categories [ ui_category ] -> refs == ui_selected ) {
+ // can't go any more up, we're at the head
+
+ } else {
+ // figure out the previous item; yay for singly linked list :/
+ mm_appref_t *i = g_categories [ ui_category ] -> refs;
+ while ( i ) {
+ if ( i -> next == ui_selected ) {
+ ui_selected = i;
+ break;
+ }
+ i = i -> next;
+ }
+
+ }
+
+ // for list view.. we're done
+ ui_set_selected ( ui_selected );
+ return;
+ }
+
// what row we in?
unsigned int row = ui_determine_row ( ui_selected );
}
void ui_push_down ( void ) {
+
+ if ( ui_viewmode == uiv_list ) {
+
+ if ( ui_selected ) {
+
+ if ( ui_selected -> next ) {
+ ui_selected = ui_selected -> next;
+ }
+
+ } else {
+ ui_selected = g_categories [ ui_category ] -> refs; // frist!
+ }
+
+ // list view? we're done.
+ ui_set_selected ( ui_selected );
+ return;
+ }
+
unsigned char col_max = ui_display_context.col_max;
if ( ui_selected ) {
return;
}
+ // cache the category/app so we can come back to it another time
+ if ( ui_selected ) {
+ pnd_conf_set_char ( g_conf, "minimenu.last_known_app_uid", ui_selected -> ref -> unique_id );
+ }
+ if ( g_categories [ 0 ] ) {
+ pnd_conf_set_char ( g_conf, "minimenu.last_known_catname", g_categories [ ui_category ] -> catname );
+
+ // and also the parent cat..
+ if ( g_categories [ ui_category ] -> parent_catname ) {
+ pnd_conf_set_char ( g_conf, "minimenu.last_known_parentcatname", g_categories [ ui_category ] -> parent_catname );
+ } else {
+ char *kv = pnd_box_find_by_key ( g_conf, "minimenu.last_known_parentcatname" );
+ if ( kv ) {
+ pnd_box_delete_node ( g_conf, kv );
+ }
+
+ }
+ }
+
+ // cache last known cat/app to /tmp, so we can use it again later
+ conf_write ( g_conf, CONF_PREF_TEMPPATH );
+
// was this icon generated from filesystem, or from pnd-file?
if ( ui_selected -> ref -> object_flags & PND_DISCO_GENERATED ) {
return;
}
+ if ( g_icon_thread_busy ) {
+ ui_stop_defered_icon_thread();
+ }
+
if ( ui_category > 0 ) {
ui_category--;
category_fs_restock ( g_categories [ ui_category ] );
ui_rows_scrolled_down = 0;
render_mask |= CHANGED_CATEGORY;
+ ui_start_defered_icon_thread();
return;
}
return;
}
+ if ( g_icon_thread_busy ) {
+ ui_stop_defered_icon_thread();
+ }
+
unsigned int screen_width = ui_display_context.screen_width;
unsigned int tab_width = pnd_conf_get_as_int ( g_conf, "tabs.tab_width" );
ui_rows_scrolled_down = 0;
render_mask |= CHANGED_CATEGORY;
+ ui_start_defered_icon_thread();
return;
}
render_mask |= CHANGED_SELECTION;
+ // preview pic stuff
+ //
+
if ( ! pnd_conf_get_as_int_d ( g_conf, "minimenu.load_previews_later", 0 ) ) {
return; // no desire to defer anything
}
render_mask |= CHANGED_CATEGORY;
// rescan the dir
category_fs_restock ( g_categories [ ui_category ] );
+ ui_start_defered_icon_thread();
}
break;
while ( 1 ) {
// pause...
- sleep ( delay_s );
+ //sleep ( delay_s );
+ SDL_Delay ( delay_s * 1000 );
// .. trigger SD check
SDL_Event e;
return ( 0 );
}
-SDL_Thread *g_icon_thread = NULL;
void ui_post_scan ( void ) {
- // if deferred icon load, kick off the thread now
- if ( pnd_conf_get_as_int_d ( g_conf, "minimenu.load_icons_later", 0 ) == 1 ) {
-
- g_icon_thread = SDL_CreateThread ( (void*)ui_threaded_defered_icon, NULL );
-
- if ( ! g_icon_thread ) {
- pnd_log ( pndn_error, "ERROR: Couldn't create icon thread\n" );
- }
-
- } // deferred icon load
-
// reset view
ui_selected = NULL;
ui_rows_scrolled_down = 0;
ui_category = 0;
ui_catshift = 0;
- // do we have a preferred category to jump to?
+ // do we have a preferred category to jump to? or a last known one?
char *dc = pnd_conf_get_as_char ( g_conf, "categories.default_cat" );
- if ( dc ) {
+ char *lastcat = pnd_conf_get_as_char ( g_conf, "minimenu.last_known_catname" );
+ if ( ( dc ) ||
+ ( pnd_conf_get_as_int_d ( g_conf, "minimenu.start_selected", 0 ) && lastcat ) )
+ {
+ char *catpick = NULL;
+
+ if ( pnd_conf_get_as_int_d ( g_conf, "minimenu.start_selected", 0 ) && lastcat ) {
+ catpick = lastcat;
+
+ // if this is a subcat, we have some doctoring to do :/ the hackishness is really
+ // starting to show..
+ if ( pnd_conf_get_as_char ( g_conf, "minimenu.last_known_parentcatname" ) ) {
+ // in subcat view, we only have one cat
+ ui_category = 0;
+ ui_catshift = 0;
+ // the cat name to search for is Child*Parent
+ char key [ 512 ];
+ sprintf ( key, "%s*%s",
+ pnd_conf_get_as_char ( g_conf, "minimenu.last_known_catname" )
+ , pnd_conf_get_as_char ( g_conf, "minimenu.last_known_parentcatname" ) );
+ category_publish ( CFBYNAME, key );
+ // since we forced it by hand, no need to do a cat-scan below
+ catpick = NULL;
+ }
+
+ } else if ( dc ) {
+ catpick = dc;
+ }
// attempt to find default cat; if we do find it, select it; otherwise
// default behaviour will pick first cat (ie: usually All)
- unsigned int i;
- for ( i = 0; i < g_categorycount; i++ ) {
- if ( strcasecmp ( g_categories [ i ] -> catname, dc ) == 0 ) {
- ui_category = i;
- // ensure visibility
- unsigned int screen_width = ui_display_context.screen_width;
- unsigned int tab_width = pnd_conf_get_as_int ( g_conf, "tabs.tab_width" );
- if ( ui_category > ui_catshift + ( screen_width / tab_width ) - 1 ) {
- ui_catshift = ui_category - ( screen_width / tab_width ) + 1;
+ if ( catpick ) {
+ unsigned int i;
+
+ for ( i = 0; i < g_categorycount; i++ ) {
+ if ( strcasecmp ( g_categories [ i ] -> catname, catpick ) == 0 ) {
+ ui_category = i;
+ // ensure visibility
+ unsigned int screen_width = ui_display_context.screen_width;
+ unsigned int tab_width = pnd_conf_get_as_int ( g_conf, "tabs.tab_width" );
+ if ( ui_category > ui_catshift + ( screen_width / tab_width ) - 1 ) {
+ ui_catshift = ui_category - ( screen_width / tab_width ) + 1;
+ }
+ break;
}
- break;
}
- }
- if ( i == g_categorycount ) {
- pnd_log ( pndn_warning, " User defined default category '%s' but not found, so using default behaviour\n", dc );
- }
+ if ( i == g_categorycount ) {
+ pnd_log ( pndn_warning, " User defined default category or last known cat '%s' but not found, so using default behaviour\n", catpick );
+ }
+
+ } // cat change?
} // default cat
// if we're sent right to a dirbrowser tab, restock it now (normally we restock on entry)
- if ( g_categories [ ui_category ] -> fspath ) {
+ if ( g_categories [ ui_category ] && g_categories [ ui_category ] -> fspath ) {
printf ( "Restock on start: '%s'\n", g_categories [ ui_category ] -> fspath );
category_fs_restock ( g_categories [ ui_category ] );
}
// redraw all
render_mask |= CHANGED_EVERYTHING;
+ // if deferred icon load, kick off the thread now
+ if ( pnd_conf_get_as_int_d ( g_conf, "minimenu.load_icons_later", 0 ) == 1 ) {
+ ui_start_defered_icon_thread();
+ } // deferred icon load
+
return;
}
unsigned char ui_threaded_defered_icon ( void *p ) {
extern pnd_box_handle g_active_apps;
- pnd_box_handle h = g_active_apps;
unsigned char maxwidth, maxheight;
maxwidth = pnd_conf_get_as_int_d ( g_conf, "grid.icon_max_width", 50 );
maxheight = pnd_conf_get_as_int_d ( g_conf, "grid.icon_max_height", 50 );
- pnd_disco_t *iter = pnd_box_get_head ( h );
+ pnd_disco_t *iter;
+
+ g_icon_thread_busy = 1;
+
+ // work at it in order within current category
- while ( iter ) {
+ mm_appref_t *refiter = g_categories [ ui_category ] ? g_categories [ ui_category ] -> refs : NULL;
+ while ( refiter && ! g_icon_thread_stop ) {
+ iter = refiter -> ref;
- // cache it
- if ( iter -> pnd_icon_pos &&
- ! cache_icon ( iter, maxwidth, maxheight ) )
+ // has an icon that is not already cached?
+ if ( ( iter -> pnd_icon_pos ) ||
+ ( iter -> icon && iter -> object_flags & PND_DISCO_LIBPND_DD )
+ )
{
- pnd_log ( pndn_warning, " Couldn't load icon: '%s'\n", IFNULL(iter->title_en,"No Name") );
- } else {
+
+ // try to cache it?
+ if ( ! cache_icon ( iter, maxwidth, maxheight ) ) {
+ //pnd_log ( pndn_warning, " Couldn't load icon: '%s'\n", IFNULL(iter->title_en,"No Name") );
- // trigger that we completed
- SDL_Event e;
- bzero ( &e, sizeof(SDL_Event) );
- e.type = SDL_USEREVENT;
- e.user.code = sdl_user_finishedicon;
- SDL_PushEvent ( &e );
+ } else {
- //pnd_log ( pndn_warning, " Finished deferred load icon: '%s'\n", IFNULL(iter->title_en,"No Name") );
- usleep ( pnd_conf_get_as_int_d ( g_conf, "minimenu.defer_icon_us", 50000 ) );
+ // trigger that we completed
+ SDL_Event e;
+ bzero ( &e, sizeof(SDL_Event) );
+ e.type = SDL_USEREVENT;
+ e.user.code = sdl_user_finishedicon;
+ SDL_PushEvent ( &e );
- }
+ //pnd_log ( pndn_warning, " Finished deferred load icon: '%s'\n", IFNULL(iter->title_en,"No Name") );
+ //usleep ( pnd_conf_get_as_int_d ( g_conf, "minimenu.defer_icon_us", 50000 ) );
- // next
- iter = pnd_box_get_next ( iter );
- } // while
+ }
+
+ // avoid churn
+ iter -> pnd_icon_pos = 0;
+ if ( iter -> icon ) {
+ free ( iter -> icon );
+ iter -> icon = NULL;
+ }
+
+ // let user do something..
+ SDL_Delay ( 200 );
+
+ } // has icon
+
+ refiter = refiter -> next;
+ }
+
+ // mark as done
+ g_icon_thread_busy = 0;
return ( 0 );
}
if ( sel >= 0 ) {
// fix up category name, if its been hacked
+#if 0 // prepending and .. wtf crap is this
if ( strchr ( g_categories [ sel ] -> catname, '.' ) ) {
char *t = g_categories [ sel ] -> catname;
g_categories [ sel ] -> catname = strdup ( strchr ( g_categories [ sel ] -> catname, '.' ) + 1 );
free ( t );
}
+#endif
// reflag this guy to be visible
g_categories [ sel ] -> catflags = CFNORMAL;
ui_catshift = ui_category - ( screen_width / tab_width ) + 1;
}
- // redraw tabs
- render_mask |= CHANGED_CATEGORY;
}
- for ( i = 0; i < g_categorycount; i++ ) {
- free ( labels [ i ] );
- }
+ // republish categories
+ category_publish ( CFNORMAL, NULL );
+
+ // redraw tabs
+ render_mask |= CHANGED_CATEGORY;
+ ui_start_defered_icon_thread();
return;
}
SDL_Color tmp = { c -> font_rgba_r, c -> font_rgba_g, c -> font_rgba_b, c -> font_rgba_a };
c -> fontcolor = tmp;
+ // determine font height
+ if ( g_grid_font ) {
+ SDL_Surface *rtext;
+ rtext = TTF_RenderText_Blended ( g_grid_font, "M", c -> fontcolor );
+ c -> text_height = rtext -> h;
+ } else {
+ c -> text_height = 10;
+ }
+
// now that we've got 'normal' (detail pane shown) param's, lets check if detail pane
// is hidden; if so, override some values with those alternate skin values where possible.
if ( ui_detail_hidden ) {
context_app_rename,
context_app_cpuspeed,
context_app_run,
+ context_app_notes1,
+ context_app_notes2,
+ context_app_notes3,
context_menu_max
};
"Recategorize subcategory", // recategorize
"Change displayed title", // rename
"Set CPU speed for launch", // cpuspeed
- "Run application" // run
+ "Run application", // run
+ "Edit notes line 1", // notes1
+ "Edit notes line 2", // notes2
+ "Edit notes line 3", // notes3
};
unsigned short int menu [ context_menu_max ];
menu [ menumax ] = context_file_info; menustring [ menumax++ ] = verbiage [ context_file_info ];
menu [ menumax ] = context_file_delete; menustring [ menumax++ ] = verbiage [ context_file_delete ];
} else {
+
+ if ( a -> ref -> object_type == pnd_object_type_directory ) {
+ return; // don't do anything if the guy is a subcat-as-folder
+ }
+
//menu [ menumax ] = context_app_info; menustring [ menumax++ ] = verbiage [ context_app_info ];
menu [ menumax ] = context_app_run; menustring [ menumax++ ] = verbiage [ context_app_run ];
menu [ menumax ] = context_app_hide; menustring [ menumax++ ] = verbiage [ context_app_hide ];
menu [ menumax ] = context_app_recategorize_sub; menustring [ menumax++ ] = verbiage [ context_app_recategorize_sub ];
menu [ menumax ] = context_app_rename; menustring [ menumax++ ] = verbiage [ context_app_rename ];
menu [ menumax ] = context_app_cpuspeed; menustring [ menumax++ ] = verbiage [ context_app_cpuspeed ];
+ menu [ menumax ] = context_app_notes1; menustring [ menumax++ ] = verbiage [ context_app_notes1 ];
+ menu [ menumax ] = context_app_notes2; menustring [ menumax++ ] = verbiage [ context_app_notes2 ];
+ menu [ menumax ] = context_app_notes3; menustring [ menumax++ ] = verbiage [ context_app_notes3 ];
}
// operate the menu
// write conf, so it will take next time
conf_write ( g_conf, conf_determine_location ( g_conf ) );
+ conf_write ( g_conf, CONF_PREF_TEMPPATH );
+
+ // can we just 'hide' this guy without reloading all apps? (this is for you, EvilDragon)
+ if ( 0 ) {
+ //
+ // DOESN'T WORK YET; other parts of app are still hanging onto some values and blow up
+ //
+ char *uid = strdup ( a -> ref -> unique_id );
+ unsigned int i;
+ for ( i = 0; i < g_categorycount; i++ ) {
+ mm_appref_t *p = g_categories [ i ] -> refs;
+ mm_appref_t *n;
+ while ( p ) {
+ n = p -> next;
+
+ if ( strcmp ( p -> ref -> unique_id, uid ) == 0 ) {
+ free ( p );
+ if ( g_categories [ i ] -> refcount ) {
+ g_categories [ i ] -> refcount--;
+ }
+ }
+
+ p = n;
+ } // while for each appref
+ } // for each cat/tab
+
+ free ( uid );
+
+ } else {
+ // request rescan and wrap up
+ rescan_apps++;
+ }
- // request rescan and wrap up
- rescan_apps++;
context_alive = 0; // nolonger visible, so lets just get out
}
-
+
break;
case context_app_recategorize:
unsigned char optmax = 0;
unsigned char i;
- i = 0;
+ // show custom categories
+ if ( mmcustom_setup() ) {
+
+ for ( i = 0; i < mmcustom_count; i++ ) {
+ if ( mmcustom_complete [ i ].parent_cat == NULL ) {
+ opts [ optmax++ ] = mmcustom_complete [ i ].cat;
+ }
+ }
+
+ }
+
+ // show FD categories
+ i = 2; // skip first two - Other and NoParentCategory
while ( 1 ) {
if ( ! freedesktop_complete [ i ].cat ) {
i++;
} // while
+ // picker
char prompt [ 101 ];
snprintf ( prompt, 100, "Pick category [%s]", a -> ref -> main_category ? a -> ref -> main_category : "NoParentCategory" );
if ( ui_menu_twoby ( confirm, "B/enter; other to cancel", "Confirm categorization", "Do not set category" ) == 1 ) {
ovr_replace_or_add ( a, "maincategory", opts [ sel ] );
rescan_apps++;
+ // when changing main cat, reset subcat, otherwise you go from Game/Emu to Network/Emu and get sent to Other right away
+ ovr_replace_or_add ( a, "maincategorysub1", freedesktop_complete [ 2 ].cat );
}
}
+ if ( mmcustom_is_ready() ) {
+ mmcustom_shutdown();
+ }
+
}
break;
{
char *opts [ 250 ];
unsigned char optmax = 0;
- unsigned char i;
+ unsigned char i = 0;
+
+ char *whichparentarewe;
+ if ( g_categories [ ui_category ] -> parent_catname ) {
+ whichparentarewe = g_categories [ ui_category ] -> parent_catname;
+ } else {
+ whichparentarewe = g_categories [ ui_category ] -> catname;
+ }
- i = 0;
+ // add NoSubcategory magic one
+ opts [ optmax++ ] = freedesktop_complete [ 2 ].cat;
+
+ // add custom categories
+ if ( mmcustom_setup() ) {
+
+ for ( i = 0; i < mmcustom_count; i++ ) {
+ if ( mmcustom_complete [ i ].parent_cat && strcmp ( mmcustom_complete [ i ].parent_cat, whichparentarewe ) == 0 ) {
+ opts [ optmax++ ] = mmcustom_complete [ i ].cat;
+ }
+ }
+
+ }
+
+ // add FD categories
while ( 1 ) {
if ( ! freedesktop_complete [ i ].cat ) {
break;
}
- if ( freedesktop_complete [ i ].parent_cat ) {
+ if ( ( freedesktop_complete [ i ].parent_cat ) &&
+ ( strcasecmp ( freedesktop_complete [ i ].parent_cat, whichparentarewe ) == 0 )
+ )
+ {
opts [ optmax++ ] = freedesktop_complete [ i ].cat;
}
} // while
char prompt [ 101 ];
- snprintf ( prompt, 100, "Pick subcategory [%s]", a -> ref -> main_category1 ? a -> ref -> main_category1 : "NoSubcategory" );
+ //snprintf ( prompt, 100, "Currently: %s", a -> ref -> main_category1 ? a -> ref -> main_category1 : "NoSubcategory" );
+ snprintf ( prompt, 100, "%s [%s]", a -> ref -> main_category1 ? a -> ref -> main_category1 : "NoSubcategory", whichparentarewe );
int sel = ui_modal_single_menu ( opts, optmax, prompt /*"Select subcategory"*/, "Enter to select; other to skip." );
}
+ if ( mmcustom_is_ready() ) {
+ mmcustom_shutdown();
+ }
+
}
break;
ui_push_exec();
break;
+ case context_app_notes1:
+ case context_app_notes2:
+ case context_app_notes3:
+ {
+ char namebuf [ 101 ] = "";
+
+ char key [ 501 ];
+ unsigned char notenum;
+
+ // which note line?
+ if ( menu [ sel ] == context_app_notes1 ) {
+ notenum = 1;
+ } else if ( menu [ sel ] == context_app_notes2 ) {
+ notenum = 2;
+ } else if ( menu [ sel ] == context_app_notes3 ) {
+ notenum = 3;
+ }
+
+ // figure out key for looking up existing, and for storing replacement
+ snprintf ( key, 500, "Application-%u.note-%u", a -> ref -> subapp_number, notenum );
+
+ // do we have existing value?
+ if ( a -> ovrh ) {
+ char *existing = pnd_conf_get_as_char ( a -> ovrh, key );
+ if ( existing ) {
+ strncpy ( namebuf, existing, 100 );
+ }
+ }
+
+ unsigned char changed;
+
+ changed = ui_menu_get_text_line ( "Enter replacement note", "Use keyboard; Enter when done.",
+ namebuf, namebuf, 30, 0 /* not-numeric-forced */ );
+
+ if ( changed ) {
+ ovr_replace_or_add ( a, strchr ( key, '.' ) + 1, namebuf );
+ rescan_apps++;
+ }
+
+ }
+ break;
+
default:
return;
return;
}
+unsigned char ui_menu_oneby ( char *title, char *footer, char *one ) {
+ char *opts [ 2 ];
+ opts [ 0 ] = one;
+ int sel = ui_modal_single_menu ( opts, 1, title, footer );
+ if ( sel < 0 ) {
+ return ( 0 );
+ }
+ return ( sel + 1 );
+}
+
unsigned char ui_menu_twoby ( char *title, char *footer, char *one, char *two ) {
char *opts [ 3 ];
opts [ 0 ] = one;
bzero ( rects, sizeof(SDL_Rect) * 40 );
if ( initialvalue ) {
- strncpy ( r_buffer, initialvalue, maxlen );
+ if ( initialvalue == r_buffer ) {
+ // already good to go
+ } else {
+ strncpy ( r_buffer, initialvalue, maxlen );
+ }
} else {
bzero ( r_buffer, maxlen );
}
char *eol = strchr ( r_buffer, '\0' );
*( eol - 1 ) = '\0';
}
+
+ } else if ( event.key.keysym.sym == SDLK_UP ) {
+ r_buffer [ 0 ] = '\0'; // truncate!
+
} else if ( event.key.keysym.sym == SDLK_RETURN || event.key.keysym.sym == SDLK_END ) { // return, or "B"
- return ( 1 );
+ // on Enter/Return or B, if the buffer has 1 or more chars, we return it as valid.. otherwise, invalid.
+ if ( strlen ( r_buffer ) > 0 ) {
+ return ( 1 );
+ }
+ return ( 0 );
} else if ( event.key.keysym.sym == SDLK_LSHIFT || event.key.keysym.sym == SDLK_RSHIFT ) {
shifted = 1;
} // while waiting for input
} // while
-
+
return ( 0 );
}
unsigned char ovr_replace_or_add ( mm_appref_t *a, char *keybase, char *newvalue ) {
- printf ( "setting %s:%u - '%s' to '%s' - %s/%s\n", a -> ref -> title_en, a -> ref -> subapp_number, keybase, newvalue, a -> ref -> object_path, a -> ref -> object_filename );
+ //printf ( "setting %s:%u - '%s' to '%s' - %s/%s\n", a -> ref -> title_en, a -> ref -> subapp_number, keybase, newvalue, a -> ref -> object_path, a -> ref -> object_filename );
char fullpath [ PATH_MAX ];
if ( dot ) {
sprintf ( dot, PXML_SAMEPATH_OVERRIDE_FILEEXT );
} else {
- fprintf ( stderr, "ERROR: Bad pnd-path in disco_t! %s\n", fullpath );
+ pnd_log ( pndn_error, "ERROR: Bad pnd-path in disco_t! %s\n", fullpath );
return ( 0 );
}
return ( 1 );
}
+
+void ui_manage_categories ( void ) {
+ unsigned char require_app_scan = 0;
+
+ if ( ! mmcustom_setup() ) {
+ return; // error
+ }
+
+ char *opts [ 20 ] = {
+ "List custom categories",
+ "List custom subcategories",
+ "Register custom category",
+ "Register custom subcategory",
+ "Unregister custom category",
+ "Unregister custom subcategory",
+ "Done"
+ };
+
+ while ( 1 ) {
+
+ int sel = ui_modal_single_menu ( opts, 7, "Custom Categories", "B to select; other to cancel." );
+
+ switch ( sel ) {
+
+ case 0: // list custom
+ ui_pick_custom_category ( 0 );
+ break;
+
+ case 1: // list custom sub
+ if ( mmcustom_count ) {
+
+ char *maincat = ui_pick_custom_category ( 2 );
+
+ if ( maincat ) {
+ unsigned int subcount = mmcustom_count_subcats ( maincat );
+ char titlebuf [ 201 ];
+
+ snprintf ( titlebuf, 200, "Category: %s", maincat );
+
+ if ( subcount == 0 ) {
+ ui_menu_oneby ( titlebuf, "B/Enter to accept", "Category has no subcategories." );
+ } else {
+
+ char **list = malloc ( subcount * sizeof(char*) );
+ int i;
+ unsigned int counter = 0;
+
+ for ( i = 0; i < mmcustom_count; i++ ) {
+ if ( mmcustom_complete [ i ].parent_cat && strcasecmp ( mmcustom_complete [ i ].parent_cat, maincat ) == 0 ) {
+ list [ counter++ ] = mmcustom_complete [ i ].cat;
+ }
+ }
+
+ ui_modal_single_menu ( list, counter, titlebuf, "Any button to exit." );
+
+ free ( list );
+
+ } // more than 0 subcats?
+
+ } // user picked a main cat?
+
+ } else {
+ ui_menu_oneby ( "Warning", "B/Enter to accept", "There are none registered." );
+ }
+ break;
+
+ case 2: // register custom
+ {
+ unsigned char changed;
+ char namebuf [ 101 ] = "";
+
+ changed = ui_menu_get_text_line ( "Enter unique category name", "Use keyboard; Enter when done.",
+ "Pandora", namebuf, 30, 0 /* alphanumeric */ );
+
+ // did the user enter something?
+ if ( changed ) {
+
+ // for now, force use of '*' into something else as we use * internally :/ (FIXME)
+ {
+ char *fixme;
+ while ( ( fixme = strchr ( namebuf, '*' ) ) ) {
+ *fixme = '_';
+ }
+ }
+
+ // and if so, is it existant already or not?
+ if ( mmcustom_query ( namebuf, NULL ) ) {
+ ui_menu_oneby ( "Warning", "B/Enter to accept", "Already a registered category." );
+ } else if ( freedesktop_category_query ( namebuf, NULL ) ) {
+ ui_menu_oneby ( "Warning", "B/Enter to accept", "Already a Standard category." );
+ } else {
+
+ char confirm [ 1001 ];
+ snprintf ( confirm, 1000, "Confirm: %s", namebuf );
+
+ if ( ui_menu_twoby ( confirm, "B/enter; other to cancel", "Confirm new category", "Do not register" ) == 1 ) {
+ // register, save, recycle the current list
+ mmcustom_register ( namebuf, NULL );
+ mmcustom_write ( NULL );
+ mmcustom_shutdown();
+ mmcustom_setup();
+ }
+
+ } // dupe?
+
+ } // entered something?
+
+ }
+ break;
+
+ case 3: // register custom sub
+ if ( 1 /*mmcustom_count -- we allow FD cats now, so this isn't applicable error */ ) {
+
+ char *maincat = ui_pick_custom_category ( 1 /* include FD */ );
+
+ if ( maincat ) {
+ char titlebuf [ 201 ];
+
+ snprintf ( titlebuf, 200, "Subcat of: %s", maincat );
+
+ unsigned char changed;
+ char namebuf [ 101 ] = "";
+
+ changed = ui_menu_get_text_line ( titlebuf, "Use keyboard; Enter when done.", "Submarine", namebuf, 30, 0 /* alphanumeric */ );
+
+ // did the user enter something?
+ if ( changed ) {
+
+ // for now, force use of '*' into something else as we use * internally :/ (FIXME)
+ {
+ char *fixme;
+ while ( ( fixme = strchr ( namebuf, '*' ) ) ) {
+ *fixme = '_';
+ }
+ }
+
+ // and if so, is it existant already or not?
+ if ( mmcustom_query ( namebuf, maincat ) ) {
+ ui_menu_oneby ( "Warning", "B/Enter to accept", "Already a subcategory." );
+ } else if ( freedesktop_category_query ( namebuf, maincat ) ) {
+ ui_menu_oneby ( "Warning", "B/Enter to accept", "Already a Standard subcategory." );
+ } else {
+
+ char confirm [ 1001 ];
+ snprintf ( confirm, 1000, "Confirm: %s [%s]", namebuf, maincat );
+
+ if ( ui_menu_twoby ( confirm, "B/enter; other to cancel", "Confirm new category", "Do not register" ) == 1 ) {
+ // register, save, recycle the current list
+ mmcustom_register ( namebuf, maincat );
+ mmcustom_write ( NULL );
+ mmcustom_shutdown();
+ mmcustom_setup();
+ }
+
+ } // dupe?
+
+ } // entered something?
+
+ } // selected parent cat?
+
+ } else {
+ ui_menu_oneby ( "Warning", "B/Enter to accept", "No categories registered." );
+ }
+ break;
+
+ case 4: // unreg custom
+ if ( mmcustom_count ) {
+ char *maincat = ui_pick_custom_category ( 0 );
+
+ if ( maincat ) {
+ char confirm [ 1001 ];
+ snprintf ( confirm, 1000, "Confirm remove: %s", maincat );
+
+ if ( ui_menu_twoby ( confirm, "B/enter; other to cancel", "Confirm unregister", "Do not unregister" ) == 1 ) {
+ // register, save, recycle the current list
+ mmcustom_unregister ( maincat, NULL );
+ mmcustom_write ( NULL );
+ mmcustom_shutdown();
+ mmcustom_setup();
+ }
+
+ } // picked?
+
+ } else {
+ ui_menu_oneby ( "Warning", "B/Enter to accept", "There are none registered." );
+ }
+ break;
+
+ case 5: // unreg custom sub
+ if ( mmcustom_count ) {
+ char *maincat = ui_pick_custom_category ( 2 );
+
+ if ( maincat ) {
+ unsigned int subcount = mmcustom_count_subcats ( maincat );
+ char titlebuf [ 201 ];
+
+ snprintf ( titlebuf, 200, "Category: %s", maincat );
+
+ if ( subcount == 0 ) {
+ ui_menu_oneby ( titlebuf, "B/Enter to accept", "Category has no subcategories." );
+ } else {
+
+ char **list = malloc ( subcount * sizeof(char*) );
+ int i;
+ unsigned int counter = 0;
+
+ for ( i = 0; i < mmcustom_count; i++ ) {
+ if ( mmcustom_complete [ i ].parent_cat && strcasecmp ( mmcustom_complete [ i ].parent_cat, maincat ) == 0 ) {
+ list [ counter++ ] = mmcustom_complete [ i ].cat;
+ }
+ }
+
+ int sel = ui_modal_single_menu ( list, counter, titlebuf, "B to selct; other to exit." );
+
+ if ( sel >= 0 ) {
+ char confirm [ 1001 ];
+ snprintf ( confirm, 1000, "Confirm remove: %s", list [ sel ] );
+
+ if ( ui_menu_twoby ( confirm, "B/enter; other to cancel", "Confirm unregister", "Do not unregister" ) == 1 ) {
+ // register, save, recycle the current list
+ mmcustom_unregister ( list [ sel ], maincat );
+ mmcustom_write ( NULL );
+ mmcustom_shutdown();
+ mmcustom_setup();
+ }
+
+ } // confirm kill?
+
+ free ( list );
+
+ } // more than 0 subcats?
+
+ } // user picked a main cat?
+
+ } else {
+ ui_menu_oneby ( "Warning", "B/Enter to accept", "There are none registered." );
+ }
+ break;
+
+ } // switch
+
+ // exeunt
+ if ( sel < 0 || sel > 5 ) {
+ break;
+ }
+
+ } // while running the menu
+
+ // shut down custom cats
+ mmcustom_shutdown();
+
+ // reload apps?
+ if ( require_app_scan ) {
+ applications_free();
+ applications_scan();
+ }
+
+ // redraw
+ render_mask |= CHANGED_EVERYTHING;
+
+ return;
+}
+
+// mode 0 == custom main only; 1 == custom main + FD main; 2 == custom main + FD mains-with-custom-subs
+char *ui_pick_custom_category ( unsigned char mode ) {
+ char **list;
+ int i;
+ unsigned int counter = 0;
+
+ // alloc space for list, depending on scope
+ if ( mode > 0 ) {
+ list = malloc ( (mmcustom_count+freedesktop_count()) * sizeof(char*) );
+ } else {
+ list = malloc ( mmcustom_count * sizeof(char*) );
+ }
+
+ // add custom mains
+ for ( i = 0; i < mmcustom_count; i++ ) {
+ if ( mmcustom_complete [ i ].parent_cat == NULL ) {
+ list [ counter++ ] = mmcustom_complete [ i ].cat;
+ }
+ }
+
+ // add FD if needed
+ if ( mode > 0 ) {
+ i = 3;
+
+ while ( 1 ) {
+
+ if ( ! freedesktop_complete [ i ].cat ) {
+ break;
+ }
+
+ // if FD main cat
+ if ( freedesktop_complete [ i ].parent_cat == NULL ) {
+
+ // mode 1 == include them all
+ // mode 2 == include them if they have a custom subcat
+ if ( ( mode == 1 ) ||
+ ( mmcustom_subcount ( freedesktop_complete [ i ].cat ) ) )
+ {
+ list [ counter++ ] = freedesktop_complete [ i ].cat;
+ }
+
+ } // if parent cat
+
+ i++;
+ } // while
+
+ } // if
+
+ // we actually showing anything?
+ if ( ! counter ) {
+ ui_menu_oneby ( "Warning", "B/Enter to accept", "There are none registered." );
+ return ( NULL );
+ }
+
+ // do it
+ int sel = ui_modal_single_menu ( list, counter, "Custom Categories", "Any button to exit." );
+
+ if ( sel < 0 ) {
+ free ( list );
+ return ( NULL );
+ }
+
+ char *foo = list [ sel ];
+ free ( list );
+
+ return ( foo );
+}
+
+void ui_start_defered_icon_thread ( void ) {
+
+ if ( pnd_conf_get_as_int_d ( g_conf, "minimenu.load_icons_later", 0 ) != 1 ) {
+ return;
+ }
+
+ if ( g_icon_thread_busy ) {
+ //fprintf ( stderr, "REM: Waiting for thread to stop..\n" );
+ ui_stop_defered_icon_thread();
+ }
+
+ //fprintf ( stderr, "WARN: Starting new icon caching thread..\n" );
+ g_icon_thread = SDL_CreateThread ( (void*)ui_threaded_defered_icon, NULL );
+
+ if ( ! g_icon_thread ) {
+ pnd_log ( pndn_error, "ERROR: Couldn't create icon thread\n" );
+ }
+
+ return;
+}
+
+void ui_stop_defered_icon_thread ( void ) {
+ time_t started = time ( NULL );
+
+ // ask thread to stop, then wait for it (if two run at same time, or if we change
+ // category content under neath it, could be bad..)
+ g_icon_thread_stop = 1;
+ while ( g_icon_thread_busy ) {
+ time ( NULL ); // spin
+ }
+ g_icon_thread_stop = 0;
+
+ fprintf ( stderr, "REM: Thread stoppage took %u seconds.\n", (int) ( time ( NULL ) - started ) );
+
+ return;
+}