Month: January 2013

Windows Phone app closes as soon as it opens

I was recently having a problem with an app closing as soon as it started, with absolutely no error messages at all. Turns out, the ‘Startup object’ value had been cleared, leaving it at the default ‘not set’. Setting it back to the name of the Application sorted it:

Startup object selection in Visual Studio

Posted by Dan in Programming, Windows Phone, 0 comments

Auto Resize TextView for Android using Mono for Android

AutoResizeTextView Example

If you need your TextView to automatically shrink the text to fit (rather than truncating), Andreas Krings has a great solution. However, this solution is written in Java rather than C#. So here I present a version ported to Mono for Android using C#.

The implementation is pretty much identical, with a default minimum size of 10dp. The TextView will then attempt to find the largest size possible for the text that will fit the frame (the one limitation is that only the horizontal dimension is taken into account), with a maximum size of the initial size; and a minimum size of 10dp (unless overridden).  Usage is the same as well:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res/com.danclarke.AutoResizeTextView"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <TextView
        android:text="Normal TextView"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/textView1" />
    <TextView
        android:text="@string/longString"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="25dp"
        android:height="50dp" />

    <TextView
        android:text="AutoResizeTextView"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/textView2"
        android:layout_marginTop="20dp" />
    <AutoResizeTextView.Controls.AutoResizeTextView
        android:text="@string/longString"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="25dp"
        android:height="50dp" />

    <TextView
        android:text="AutoResizeTextView with minTextSize"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/textView3"
        android:layout_marginTop="20dp" />
    <AutoResizeTextView.Controls.AutoResizeTextView
        android:text="@string/longString"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="25dp"
        android:height="50dp"
        app:minTextSize="20dp" />
</LinearLayout>

Don’t forget to view the full project at GitHub!

Code Listing

For the impatient, here’s the full control’s code listing:

using System;

using Android.Content;
using Android.Runtime;
using Android.Widget;
using Android.Util;
using Android.Graphics;

namespace AutoResizeTextView.Controls
{
    /// <summary>
    /// TextView that automatically resizes it's content to fit the layout dimensions
    /// </summary>
    /// <remarks>Port of: http://ankri.de/autoscale-textview/</remarks>
    public class AutoResizeTextView : TextView
    {
        /// <summary>
        /// How close we have to be to the perfect size
        /// </summary>
        private const float Threshold = .5f;
        
        /// <summary>
        /// Default minimum text size
        /// </summary>
        private const float DefaultMinTextSize = 10f;
        
        private Paint _textPaint;
        private float _preferredTextSize;
        
        public AutoResizeTextView(Context context) : base(context)
        {
            Initialise(context, null);
        }
        
        public AutoResizeTextView(Context context, IAttributeSet attrs) : base(context, attrs)
        {
            Initialise(context, attrs);
        }
        
        public AutoResizeTextView(Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle)
        {
            Initialise(context, attrs);
        }
        
        // Default constructor override for MonoDroid
        public AutoResizeTextView(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
        {
            Initialise(null, null);
        }
        
        private void Initialise(Context context, IAttributeSet attrs)
        {
            _textPaint = new Paint();
            
            if (context != null && attrs != null)
            {
                var attributes = context.ObtainStyledAttributes(attrs, Resource.Styleable.AutoResizeTextView);
                MinTextSize = attributes.GetDimension(Resource.Styleable.AutoResizeTextView_minTextSize, DefaultMinTextSize);
                attributes.Recycle();
                
                _preferredTextSize = TextSize;
            }
        }
        
        /// <summary>
        /// Minimum text size in actual pixels
        /// </summary>
        public float MinTextSize { get; set; }
        
        /// <summary>
        /// Resize the text so that it fits.
        /// </summary>
        /// <param name="text">Text</param>
        /// <param name="textWidth">Width of the TextView</param>
        protected virtual void RefitText(string text, int textWidth)
        {
            if (textWidth <= 0 || string.IsNullOrWhiteSpace(text))
                return;
            
            int targetWidth = textWidth - PaddingLeft - PaddingRight;
            _textPaint.Set(this.Paint);
            
            while ((_preferredTextSize - MinTextSize) > Threshold)
            {
                float size = (_preferredTextSize + MinTextSize) / 2f;
                _textPaint.TextSize = size;
                
                if (_textPaint.MeasureText(text) >= targetWidth)
                    _preferredTextSize = size; // Too big
                else
                    MinTextSize = size; // Too small
            }
            
            SetTextSize(ComplexUnitType.Px, MinTextSize);
        }
        
        protected override void OnTextChanged(Java.Lang.ICharSequence text, int start, int before, int after)
        {
            base.OnTextChanged(text, start, before, after);
            
            RefitText(text.ToString(), Width);
        }
        
        protected override void OnSizeChanged(int w, int h, int oldw, int oldh)
        {
            base.OnSizeChanged(w, h, oldw, oldh);
            
            if (w != oldw)
                RefitText(Text, Width);
        }
    }
}
Posted by Dan in Mono for Android, 2 comments

Xbox 360 ‘Reference Levels’

If you’ve got an Xbox 360, chances are you’ve seen the ‘Reference Levels’ setting in display settings. This is a really badly named setting since it’s all to do with the black level the console outputs. ‘Standard’ is the setting you want if you have a quality HDTV, since standard outputs the full range without clipping. If you have a Samsung TV, set the black level to ‘lower’. The ‘Expanded’ setting clips blacks below 16 to 0, and anything above 235 to 255. This is great if your TV doesn’t work properly with HDMI signals, or you’re using VGA. Otherwise it’s actually reducing the range of colour values the console is outputting. In short use ‘standard’ and tell your TV that the black levels are really black. Otherwise if you have a ‘cheaper’ TV use the ‘Expanded’ setting.

Posted by Dan in General, 2 comments

iPhone Splash Screen Works On Simulator – Not Device

This problem is due to the case sensitivity of the iPhone device. The splash screen must be named ‘Default.png’, capital D included. Once you’ve renamed the file you need to remove the app from your device; you also need to go into the project folder and delete everything within the ‘Build’ folder.

Posted by Dan in Programming, 0 comments

Proper HTML Custom Menu in Moodle 2

If you’re developing a theme for Moodle 2, you probably want to support the new custom menu functionality. Problem is it uses YUI3 to make the menu ‘work’ rather than CSS alone. This means it’s a) Harder to style and b) results in a nasty ‘jump’ as the JS kicks in – you have to style both pre- and post- JS menu. Instead why not just output a normal nested unordered list and use CSS to provide the functionality? Well, you can! You need to add a little PHP first though. Create a file ‘renderers.php’ in your theme directory and add this code (make sure to change <theme name> to the name of your theme):

<?php
class theme_<theme name>_core_renderer extends core_renderer
{
    /**
     * Renders a custom menu object
     *
     * @staticvar int $menucount
     * @param custom_menu $menu
     * @return string
     */
    protected function render_custom_menu(custom_menu $menu) {
        static $menucount = 0;
        // If the menu has no children return an empty string
        if (!$menu->has_children()) {
            return '';
        }
        // Increment the menu count. This is used for ID's that get worked with
        // in JavaScript as is essential
        $menucount++;
        $content .= html_writer::start_tag('ul', array('class'=>'custommenu'));
        // Render each child
        foreach ($menu->get_children() as $item) {
            $content .= $this->render_custom_menu_item($item);
        }
        // Close the open tags
        $content .= html_writer::end_tag('ul');
        // Return the custom menu
        return $content;
    }
    /**
     * Renders a custom menu node as part of a submenu
     *
     * @see render_custom_menu()
     *
     * @staticvar int $submenucount
     * @param custom_menu_item $menunode
     * @return string
     */
    protected function render_custom_menu_item(custom_menu_item $menunode) {
        // Required to ensure we get unique trackable id's
        static $submenucount = 0;
        if ($menunode->has_children()) {
            // If the child has menus render it as a sub menu
            $submenucount++;
            $content = html_writer::start_tag('li');
            if ($menunode->get_url() !== null) {
                $url = $menunode->get_url();
            } else {
                $url = '#cm_submenu_'.$submenucount;
            }
            $content .= html_writer::link($url, $menunode->get_text(), array('title'=>$menunode->get_title()));
            $content .= html_writer::start_tag('ul');
            foreach ($menunode->get_children() as $menunode) {
                $content .= $this->render_custom_menu_item($menunode);
            }
            $content .= html_writer::end_tag('ul');
            $content .= html_writer::end_tag('li');
        } else {
            // The node doesn't have children so produce a final menuitem
            $content = html_writer::start_tag('li');
            if ($menunode->get_url() !== null) {
                $url = $menunode->get_url();
            } else {
                $url = '#';
            }
            $content .= html_writer::link($url, $menunode->get_text(), array('title'=>$menunode->get_title()));
            $content .= html_writer::end_tag('li');
        }
        // Return the sub menu
        return $content;
    }
}
?>

Then go into your config.php file and make sure $THEME->rendererfactory is set like so:

$THEME->rendererfactory = 'theme_overridden_renderer_factory';

And now you should have nice plain HTML output ready for styling the proper way!

Posted by Dan in PHP, 0 comments

Setting the PATH in OSX Leopard or above

Apple added a very handy .d (daemon?) directory in Leopard+ for appending to the global PATH variable. You can add to the path easily using the terminal:

sudo sh -c 'echo "[newpath]" >> /etc/paths.d/[pathname]'

For example to add the Android SDK to your path, you can enter the following command in the terminal:

sudo sh -c 'echo "/Developer/android-sdk-mac_x86" >> /etc/paths.d/AndroidPath'

OSX goes through each file in that directory, appending what it finds to the PATH. Makes installing / uninstalling utterly trivial.

All credit to dhaveconfig.

Posted by Dan in Mac, 0 comments

Detect WordPress Home Page / Front Page

Chances are you want to have slightly different content for the home page of your WordPress blog. In theory it should be easy enough, use is_home() or is_front_page(). Sadly these methods are hit and miss to say the least. Instead try using:

if ($_SERVER["REQUEST_URI"] == '/' || $_SERVER["REQUEST_URI"] == '/index.php')
{
    // Your home page specific code here
}

It’s not ideal, but it works.

Posted by Dan in PHP, 0 comments

Nslookup and /etc/hosts

Having trouble checking your /etc/hosts records with nslookup on your Mac/Linux PC? Use traceroute instead, nslookup purposely bypasses any local config. Traceroute acts like a ‘normal’ application and will pick up your /etc/hosts records.

Posted by Dan in Mac, 0 comments

Mahara Installation

[ENV] b0 Your server does not have the mime_magic extension enabled. Mahara may have trouble detecting file types.

Getting that error? You need to enable or install the fileinfo extension. If you’re on Windows, open up the php.ini file and uncomment:

extension=php_fileinfo.dll

You can now install Mahara! The mime_magic extension is no longer available in new versions of PHP.

Posted by Dan in PHP, 0 comments