#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_icons; // 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 ) {
} else {
ui_detail_hidden = 1;
}
+
+ // determine default viewmode
+ if ( pnd_conf_get_as_int_d ( g_conf, "display.viewmode_list", -1 ) != -1 ) {
+ int i = pnd_conf_get_as_int_d ( g_conf, "display.viewmode_list", 0 );
+ if ( i >= uiv_max ) {
+ ui_viewmode = uiv_icons;
+ } else {
+ ui_viewmode = i;
+ }
+ }
+
+ // update display context
ui_recache_context ( &ui_display_context );
return ( 1 );
{ 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 ) {
}
if ( ( g_imagecache [ i ].i = IMG_Load ( fullpath ) ) ) {
+
+ // also make a 'tiny' version..
+ SDL_Surface *s = g_imagecache [ i ].i;
+ SDL_Surface *scaled_tiny = SDL_ConvertSurface ( s, s -> format, s -> flags ); // duplicate
+ extern ui_context_t ui_display_context;
+ scaled_tiny = ui_scale_image ( scaled_tiny, -1 , ui_display_context.text_height_tab ); // resize
+ g_imagecache [ i ].itiny = scaled_tiny;
+
break; // no retry needed
} else {
pnd_log ( pndn_error, "ERROR: (Try %u) Couldn't load static cache image: %s\n", try + 1, fullpath );
} // 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_tab + 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_tab + c -> icon_offset_y;
+ dest -> x = c -> grid_offset_x + c -> text_clip_x;
+ dest -> y = c -> grid_offset_y + ( displayrow * ( c -> text_height_tab + 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;
+ SDL_Surface *iconsurface = NULL;
+
+ // 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..
+ }
+
+ // 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 );
+
+ }
+
+ } // load icon during rendering?
+
if ( ic ) {
- iconsurface = ic -> i;
+ iconsurface = ic -> itiny;
} else {
//pnd_log ( pndn_warning, "WARNING: TBD: Need Missin-icon icon for '%s'\n", IFNULL(appiter -> ref -> title_en,"No Name") );
// 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;
+ iconsurface = g_imagecache [ IMG_FOLDER ].itiny;
} else if ( strcmp ( appiter -> ref -> title_en, ".." ) == 0 ) {
- iconsurface = g_imagecache [ IMG_DOTDOTFOLDER ].i;
+ iconsurface = g_imagecache [ IMG_DOTDOTFOLDER ].itiny;
} else {
- iconsurface = g_imagecache [ IMG_SUBCATFOLDER ].i;
+ iconsurface = g_imagecache [ IMG_SUBCATFOLDER ].itiny;
}
} else {
- iconsurface = g_imagecache [ IMG_EXECBIN ].i;
+ iconsurface = g_imagecache [ IMG_EXECBIN ].itiny;
}
} else {
- iconsurface = g_imagecache [ IMG_ICON_MISSING ].i;
+ iconsurface = g_imagecache [ IMG_ICON_MISSING ].itiny;
}
}
- // 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++;
-
+ dest -> x = c -> grid_offset_x + c -> text_clip_x;
+ dest -> y = c -> grid_offset_y + ( displayrow * ( c -> text_height_tab + c -> icon_offset_y ) ) - ( c -> icon_offset_y / 2 );
+ SDL_BlitSurface ( iconsurface, NULL, sdl_realscreen, 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 );
+ rtext = TTF_RenderText_Blended ( g_tab_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 += 30; // so all title-text line up, regardless of icon presence
+#if 0
+ if ( ic ) {
+ dest -> x += 30; //((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_tab + 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 );
+
+ }
+
+ } // 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") );
- } // while
+ 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?
} else if ( event.key.keysym.sym == SDLK_LCTRL /*LALT*/ ) { // select button
char *opts [ 20 ] = {
+ "Toggle view icons<->list",
"Reveal hidden category",
"Shutdown Pandora",
"Configure Minimenu",
"Select a Minimenu skin",
"About Minimenu"
};
- int sel = ui_modal_single_menu ( opts, 11, "Minimenu", "Enter to select; other to return." );
+ int sel = ui_modal_single_menu ( opts, 12, "Minimenu", "Enter to select; other to return." );
char buffer [ 100 ];
if ( sel == 0 ) {
+ if ( ui_viewmode == uiv_list ) {
+ ui_viewmode = uiv_icons;
+ } else {
+ ui_viewmode = uiv_list;
+ }
+ } else if ( sel == 1 ) {
// do nothing
ui_revealscreen();
- } else if ( sel == 1 ) {
+ } else if ( sel == 2 ) {
+ // 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 );
- } else if ( sel == 2 ) {
+ } else if ( sel == 3 ) {
// 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 ) {
+ } else if ( sel == 4 ) {
// manage custom categories
ui_manage_categories();
- } else if ( sel == 4 ) {
+ } else if ( sel == 5 ) {
// rescan apps
pnd_log ( pndn_debug, "Freeing up applications\n" );
applications_free();
pnd_log ( pndn_debug, "Rescanning applications\n" );
applications_scan();
- } else if ( sel == 5 ) {
+ } else if ( sel == 6 ) {
// 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 == 6 ) {
+ } else if ( sel == 7 ) {
// run terminal
char *argv[5];
argv [ 0 ] = pnd_conf_get_as_char ( g_conf, "utility.terminal" );
ui_forkexec ( argv );
}
- } else if ( sel == 7 ) {
+ } else if ( sel == 8 ) {
char buffer [ PATH_MAX ];
sprintf ( buffer, "%s %s\n", MM_RUN, "/usr/pandora/scripts/op_switchgui.sh" );
emit_and_quit ( buffer );
- } else if ( sel == 8 ) {
- emit_and_quit ( MM_QUIT );
} else if ( sel == 9 ) {
+ emit_and_quit ( MM_QUIT );
+ } else if ( sel == 10 ) {
// select skin
if ( ui_pick_skin() ) {
emit_and_quit ( MM_RESTART );
}
- } else if ( sel == 10 ) {
+ } else if ( sel == 11 ) {
// 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_tab + 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_tab + 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 );
}
// 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;
+ }
+
+ if ( g_tab_font ) {
+ SDL_Surface *rtext;
+ rtext = TTF_RenderText_Blended ( g_tab_font, "M", c -> fontcolor );
+ c -> text_height_tab = rtext -> h;
+ } else {
+ c -> text_height_tab = 15;
+ }
+
// 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 ) {
// 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 ) {
context_alive = 0; // nolonger visible, so lets just get out
}
-
+
break;
case context_app_recategorize:
} // while waiting for input
} // while
-
+
return ( 0 );
}
switch ( sel ) {
case 0: // list custom
- if ( mmcustom_count ) {
- ui_pick_custom_category ( 0 );
- } else {
- ui_menu_oneby ( "Warning", "B/Enter to accept", "There are none registered." );
- }
+ ui_pick_custom_category ( 0 );
break;
case 1: // list custom sub
if ( mmcustom_count ) {
- char *maincat = ui_pick_custom_category ( 0 );
+ char *maincat = ui_pick_custom_category ( 2 );
if ( maincat ) {
unsigned int subcount = mmcustom_count_subcats ( maincat );
// 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." );
break;
case 3: // register custom sub
- if ( mmcustom_count ) {
+ if ( 1 /*mmcustom_count -- we allow FD cats now, so this isn't applicable error */ ) {
char *maincat = ui_pick_custom_category ( 1 /* include FD */ );
// 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." );
case 5: // unreg custom sub
if ( mmcustom_count ) {
- char *maincat = ui_pick_custom_category ( 0 );
+ char *maincat = ui_pick_custom_category ( 2 );
if ( maincat ) {
unsigned int subcount = mmcustom_count_subcats ( maincat );
return;
}
-char *ui_pick_custom_category ( unsigned char include_fd ) {
+// 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;
- if ( include_fd ) {
+ // 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
+ // 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 ( include_fd ) {
+ // 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 ) {
- list [ counter++ ] = freedesktop_complete [ i ].cat;
- }
+
+ // 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
- int sel = ui_modal_single_menu ( list, counter, "Custom Main Categories", "Any button to exit." );
+ // 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 ( 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;
+}