Iterative MenuLayer Pebble - pebble-watch

I am trying to create an app on pebble using MenuLayer. My intention is to create Menu's and then sub-menus using the MenuLayer.
I did some basic implementation using "menu_layer_set_callbacks" method and registering callbacks methods for each submenu layers. However, now I realise its getting too messy.
I want to know if there is any easy way out provided in the framework to meet this requirement.
Thanks.
KK

I don't know what you ended up with, but for my project, I made a set of sub-windows but reuses the same callbacks, you can pass custom data to let each know what type it is. Then just push the required sub-windows as needed
void sub_window_load(Window* parentWindow) {
Layer* window_layer = window_get_root_layer(parentWindow);
const GRect bounds = layer_get_frame(window_layer);
MenuLayer* new_layer = menu_layer_create(bounds);
const int context = *((int*) window_get_user_data(parentWindow));
if (context == ID_A) s_A_layer = new_layer;
else if (context == ID_B) s_B_layer = new_layer;
menu_layer_set_callbacks(new_layer, window_get_user_data(parentWindow), (MenuLayerCallbacks){
.get_num_sections = sub_menu_get_num_sections_callback,
.get_num_rows = sub_menu_get_num_rows_callback
/* etc */
});
menu_layer_set_click_config_onto_window(new_layer, parentWindow);
layer_add_child(window_layer, menu_layer_get_layer(new_layer));
}
void createSubWin(Window** w, int* context) {
*w = window_create();
window_set_user_data(*w, context);
window_set_window_handlers(*w, (WindowHandlers) {
.load = sub_window_load,
.unload = sub_window_unload
});
}

Related

UWP: calculate expected size of screenshot using multiple monitor setup

Right, parsing the clipboard, I am trying to detect if a stored bitmap in there might be the result of a screenshot the user took.
Everything is working fine as long as the user only has one monitor. Things become a bit more involved with two or more.
I am using the routing below to grab all the displays in use. Now, since I have no idea how they are configured to hang together, I do not know how to calculate the size of the screenshot (that Windows would produce) from that information.
I explicitly do not want to take a screenshot myself to compare. It's a privacy promise by my app.
Any ideas?
Here is the code for the size extractor, run in the UI thread.
public static async Task<Windows.Graphics.SizeInt32[]> GetMonitorSizesAsync()
{
Windows.Graphics.SizeInt32[] result = null;
var selector = DisplayMonitor.GetDeviceSelector();
var devices = await DeviceInformation.FindAllAsync(selector);
if (devices?.Count > 0)
{
result = new Windows.Graphics.SizeInt32[devices.Count];
int i = 0;
foreach (var device in devices)
{
var monitor = await DisplayMonitor.FromInterfaceIdAsync(device.Id);
result[i++] = monitor.NativeResolutionInRawPixels;
}
}
return result;
}
Base on Raymonds comment, here is my current solution in release code...
IN_UI_THREAD is a convenience property to see if the code executes in the UI thread,
public static Windows.Foundation.Size GetDesktopSize()
{
Int32 desktopWidth = 0;
Int32 desktopHeight = 0;
if (IN_UI_THREAD)
{
var regions = Windows.UI.ViewManagement.ApplicationView.GetForCurrentView()?.WindowingEnvironment?.GetDisplayRegions()?.Where(r => r.IsVisible);
if (regions?.Count() > 0)
{
// Get grab the most left and the most right point.
var MostLeft = regions.Min(r => r.WorkAreaOffset.X);
var MostTop = regions.Min(r => r.WorkAreaOffset.Y);
// The width is the distance between the most left and the most right point
desktopWidth = (int)regions.Max(r => r.WorkAreaOffset.X + r.WorkAreaSize.Width - MostLeft);
// Same for height
desktopHeight = (int)regions.Max(r => r.WorkAreaOffset.Y + r.WorkAreaSize.Height - MostTop);
}
}
return new Windows.Foundation.Size(desktopWidth, desktopHeight);
}

Remove repetitive fragments from fragment manager in Xamarin Android

I am working on android using Xamarin and MVVMCross framework. I want to update the remove the fragment from fragment manager to handle the back button, Because i have to navigate between screen which make a cross reference in Back Stack. So i want to remove the repetitive entries from stack. Its removing the repetitive entries from stack but it does not update the BackStackEntryCount with latest fragments.
I have written code
public override void OnFragmentChanged(IMvxCachedFragmentInfo fragmentInfo)
{
if (fragmentInfo != null)
{
var ifExists =
SupportFragmentManager.Fragments?.FirstOrDefault(x => x.Tag.ToLower() == fragmentInfo.Tag.ToLower());
if (ifExists != null)
{
var indexOf = SupportFragmentManager.Fragments.IndexOf(ifExists);
var total = SupportFragmentManager.BackStackEntryCount;
for (int i = indexOf + 1; i < total; i++)
{
SupportFragmentManager.Fragments.RemoveAt(i);
}
}
}
base.OnFragmentChanged(fragmentInfo);
}
SupportFragmentManager.Fragments is a read only property (It only has a get). Modifying the content of the list of fragment has no impact on the underline fragment backstack count.
What you can instead try is to pop the stack down to the existing fragment. This should remove all fragments above it.
var exisitngFragment = SupportFragmentManager.FindFragmentByTag(fragmentInfo.Tag);
SupportFragmentManager.PopBackStackImmediate(exisitngFragment.Id, 0);

Problems with PBL_IF_ROUND_ELSE function

I'm trying to follow the tutorial about Watchfaces creation, but I'm stuck.
I copied the code from the wiki so there shouldn't be any error whatsoever, but I'm getting this error while compiling
error: implicit declaration of function 'PBL_IF_ROUND_ELSE' [-Werror=implicit-function-declaration]
I tried to google it but I couldn't find anything useful.
This is the code
#include <pebble.h>
static Window *s_main_window;
static TextLayer *s_time_layer;
static void update_time() {
// Get a tm structure
time_t temp = time(NULL);
struct tm *tick_time = localtime(&temp);
// Write the current hours and minutes into a buffer
static char s_buffer[8];
strftime(s_buffer, sizeof(s_buffer), clock_is_24h_style() ? "%H:%M" : "%I:%M", tick_time);
// Display this time on the TextLayer
text_layer_set_text(s_time_layer, s_buffer);
}
static void tick_handler(struct tm *tick_time, TimeUnits units_changed) {
update_time();
}
static void main_window_load(Window *window) {
// Get information about the Window
Layer *window_layer = window_get_root_layer(window);
GRect bounds = layer_get_bounds(window_layer);
// Create the TextLayer with specific bounds
s_time_layer = text_layer_create(
GRect(0, PBL_IF_ROUND_ELSE(58, 52), bounds.size.w, 50));
// Improve the layout to be more like a watchface
text_layer_set_background_color(s_time_layer, GColorClear);
text_layer_set_text_color(s_time_layer, GColorBlack);
text_layer_set_text(s_time_layer, "00:00");
text_layer_set_font(s_time_layer, fonts_get_system_font(FONT_KEY_BITHAM_42_BOLD));
text_layer_set_text_alignment(s_time_layer, GTextAlignmentCenter);
// Add it as a child layer to the Window's root layer
layer_add_child(window_layer, text_layer_get_layer(s_time_layer));
}
static void main_window_unload(Window *window) {
// Destroy TextLayer
text_layer_destroy(s_time_layer);
}
static void init() {
// Create main Window element and assign to pointer
s_main_window = window_create();
// Set handlers to manage the elements inside the Window
window_set_window_handlers(s_main_window, (WindowHandlers) {
.load = main_window_load,
.unload = main_window_unload
});
// Show the Window on the watch, with animated=true
window_stack_push(s_main_window, true);
// Make sure the time is displayed from the start
update_time();
// Register with TickTimerService
tick_timer_service_subscribe(MINUTE_UNIT, tick_handler);
}
static void deinit() {
// Destroy Window
window_destroy(s_main_window);
}
int main(void) {
init();
app_event_loop();
deinit();
}
I'm using the CloudPebble SDK.
I got it, PBL_IF_ROUND_ELSE works only with 3.X SDK (I was using the 2.X).
"PBL_IF_ROUND_ELSE(58, 52)" Only works with Pebble Time or SDK3.
You can replace "PBL_IF_ROUND_ELSE(58, 52)" with a range between 0 and 100. 0 meaning it will be at the top of the screen. 100 means it will be at the bottom of the screen.
Replace the "PBL_IF_ROUND_ELSE(58, 52)" with a 0. That should do the trick. Im assuming you are trying to run this program on the aplite version?

How to Work With GUI button in unity

I want to get user input through GUI Button in unity3d unityscript. I have write this script to get user input through keyboard
var f_hor : float = Input.GetAxis("Horizontal");
//Get Vertical move - move forward or backward
var f_ver : float = Input.GetAxis("Vertical");
if (f_ver < 0) {
b_isBackward = true;
} else {
b_isBackward = false;
}
its work fine and its give me 0 and 1 accordingly..But i want the same action through GUI button.Like if i have four GUI button..and they work same as this did...I can make GUI button in ONGUI function..But how can i achieve this functionaility...Any help
Altough I don't know if it is the best way to go (Unity's gui element are not the best for ingame HUD or menu), this should do the job:
private bool buttonPressed = false;
public void Update()
{
if (buttonPressed)
{
//do what you want
buttonPressed = false;
}
}
Sorry for using C# code, but I don't know JS. It should be easy to translate tough.
public void OnGui()
{
Rect rect = new Rect(...); //your button dimension
if (GUI.Button(rect, "AButton")
{
buttonPressed = true;
}
}
EDIT:
If you want to manually handle input from mouse you can use methods of MonoBehavior such as OnMouseDown or OnMouseUp.
Alternatively you can check from inside Update if a mouse event occured, have a look at Input.GetMouseButton or similar methods of Input class.

How to know which one fired eventListener

I am loading images for a game before the game begin. So the main function sends links of images to an image loading object. This is what happen in my image loading object when I do image.load(link) in my main :
public function charge(str:String, img_x:int, img_y:int, layer:Sprite):void
{
trace("load");
urlRequest = new URLRequest(str);
loaderArray[cptDemande] = new Loader();
loaderArray[cptDemande].contentLoaderInfo.addEventListener(Event.COMPLETE, loading_done);
loaderArray[cptDemande].load(urlRequest);
posX[cptDemande] = img_x;
posY[cptDemande] = img_y;
layerArray[cptDemande] = layer;
cptDemande++;
}
The parameters img_x:int, img_y:int and layer:Sprite are related to displaying the images afterward. I am using arrays to be able to add the images to the stage when the loading is all done.
The event listener fire this function :
public function loading_done(evt:Event):void
{
cptLoaded++;
evt.currentTarget.contentLoaderInfo.removeEventListener(Event.COMPLETE, loading_done);
if((cptDemande == cptLoaded) && (isDone == true))
{
afficher();
}
}
what I want is to be able to target the good loader to remove the event listener. What I am currently using(evt.currentTarget) doesn't work and generate an error code :
1069 Property data not found on flash.display.LoaderInfo and there is no default value
Tracing evt.currentTarget shows that currentTarget is the LoaderInfo property. Try updating your code as follows:
public function loading_done(evt:Event):void
{
cptLoaded++;
// Current target IS the contentLoaderInfo
evt.currentTarget.removeEventListener(Event.COMPLETE, loading_done);
//evt.currentTarget.contentLoaderInfo.removeEventListener(Event.COMPLETE, loading_done);
if((cptDemande == cptLoaded) && (isDone == true))
{
afficher();
}
}
Just a wee tip for you while I'm at it, you could make life a lot easier for yourself by storing all the properties of your images on an Object and then pushing these onto a single Array, rather than managing a separate Array for each property.
Something like this:
private var loadedImages:Array = new Array();
public function charge(str:String, img_x:int, img_y:int, layer:Sprite):void
{
var urlRequest:URLRequest = new URLRequest(str);
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loading_done);
loader.load(urlRequest);
var imageData:Object = { };
imageData.loader = loader;
imageData.posX = img_x;
imageData.posY = img_y;
imageData.layer = layer;
// Now we have a single Array with a separate element for
// each image representing all its properties
loadedImages.push(imageData);
cptDemande++;
}

Resources