Click here to Skip to main content
15,886,518 members
Articles / Mobile Apps / Windows Mobile

Audio Book Player

Rate me:
Please Sign up or sign in to vote.
4.86/5 (36 votes)
11 Jun 2009CPOL6 min read 197.6K   3.5K   84  
Audio player designed specifically for listening to audio books
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Collections;
using System.Threading;
using System.IO;
using System.Reflection;
using Microsoft.Win32;

namespace abPlayer
{
    public struct FlyingTextItem
    {
        public int line;
        public String originalText;
        public String flyingText;
    };

    public partial class frmPlayer
    {
        // constants used for display positioning
        const int DISPLAY_TOP = 40;
        const int DISPLAY_GUTTER = 20;
        private int RECTANGLED_DISPLAY_HEIGHT = 26; 
        const int RECTANGLED_DISPLAY_TOP = 5;
        // paint resources
        Bitmap fgBMP = null;
        Graphics fgGraphics = null;
        Bitmap bgBMP = null;
        Graphics bgGraphics = null;
        IntPtr apiDC = IntPtr.Zero;
        Graphics screenGraphics = null;
        // flying text data
        FlyingTextItem[] fti = new FlyingTextItem[7];
        int flyingTextCount = 0;
        const String FLYING_TEXT_PREFIX = "     "; // 6 blanks
        const String FLYING_TEXT_SUFFIX = "        "; // 8 blanks
        const int FLYING_TEXT_WIDTH_THRESHOLD = 24;
        // text positioning information
        int textHeight;
        // tod and power font
        Font todFont = null;
        const int TOD_FONT_SIZE = 10;


        // paint
        void PaintScreen()
        {
            PaintScreen(screenGraphics);
        }
        void PaintScreen(Graphics dc)
        {
            // black out the whole paint rectangle
            bgGraphics.FillRectangle(new SolidBrush(Color.Black), 0, 0,
                bgBMP.Width, bgBMP.Height);
            if (tmr.Enabled)
            {
                // draw battery life pecentage and time of day
                DrawBatteryVolAndTOD(bgGraphics);
                // only if we are playing a playlist...
                if (Player.PlaylistCount > 0)
                {
                    DrawMediaTags(bgGraphics);
                    DrawLocation(bgGraphics);
                }
                DrawStatus(bgGraphics, Player.StatusString);
            }
            // commit the whole thing to the screen
            dc.DrawImage(bgBMP, 0, pnlTop.Height);
        }
        // flying text
        void PaintFlyingText()
        {
            for(int i = 0; i< flyingTextCount; i++)
            {
                fgGraphics.FillRectangle(new SolidBrush(Color.Black), 0, 0,
                    fgBMP.Width, fgBMP.Height);
                SizeF strWH = fgGraphics.MeasureString(fti[i].flyingText, this.Font);
                if (strWH.Width > Width)
                    fti[i].flyingText = fti[i].flyingText.Substring(1);
                else
                    fti[i].flyingText = fti[i].originalText;
                fgGraphics.DrawString(fti[i].flyingText, this.Font, new SolidBrush(TextColor),
                    0, 0);
                screenGraphics.DrawImage(fgBMP, 0, pnlTop.Height + 
                    DISPLAY_TOP + DISPLAY_GUTTER * fti[i].line,
                    new Rectangle(0, 0, Width,
                        textHeight), GraphicsUnit.Pixel);
            }
        }
        // battery volume & tod display
        void PaintBatteryVolAndTOD()
        {
            fgGraphics.FillRectangle(new SolidBrush(Color.Black), 0, 0,
                fgBMP.Width, fgBMP.Height);
            DrawBatteryVolAndTOD(fgGraphics);
            screenGraphics.DrawImage(fgBMP, 0, pnlTop.Height + RECTANGLED_DISPLAY_TOP,
               new Rectangle(0, RECTANGLED_DISPLAY_TOP, Width,
                   RECTANGLED_DISPLAY_HEIGHT + 4), GraphicsUnit.Pixel);
        }
        // show location
        void PaintLocation()
        {
            fgGraphics.FillRectangle(new SolidBrush(Color.Black), 0, 0,
                fgBMP.Width, fgBMP.Height);
            DrawLocation(fgGraphics);
            screenGraphics.DrawImage(fgBMP, 0, pnlTop.Height + DISPLAY_TOP + DISPLAY_GUTTER * 6,
                new Rectangle(0, DISPLAY_TOP + DISPLAY_GUTTER * 6, Width, textHeight), GraphicsUnit.Pixel);
        }
        // player status
        void PaintStatus(String status)
        {
            fgGraphics.FillRectangle(new SolidBrush(Color.Black), 0, 0,
                fgBMP.Width, fgBMP.Height);
            DrawStatus(fgGraphics, status);
            screenGraphics.DrawImage(fgBMP, 0, pnlTop.Height + DISPLAY_TOP + DISPLAY_GUTTER * 7 + 4,
                new Rectangle(0, DISPLAY_TOP + DISPLAY_GUTTER * 7 + 4, Width, RECTANGLED_DISPLAY_HEIGHT + 5), GraphicsUnit.Pixel);
        }
        // draws battery state & clock
        void DrawBatteryVolAndTOD(Graphics dc)
        {
            // get battery life percentage and establish relevant font color
            int batt = GetBatteryLifePercentAndSetTextColor();
            // format as string
            String str = " " + batt.ToString() + " % ";
            SizeF strWH = dc.MeasureString(str, todFont);
            int volL = (int)(strWH.Width + 24 + 3);
            // draw a rectangle around it
            dc.DrawRectangle(new Pen(SystemColors.Control, 2), 1, RECTANGLED_DISPLAY_TOP,
                (int)(strWH.Width + 2 + 24), RECTANGLED_DISPLAY_HEIGHT + 2);
            // draw the battery life percent
            dc.DrawString(str, todFont, new SolidBrush(TextColor),
               1 + 24,
               (RECTANGLED_DISPLAY_HEIGHT / 2 - strWH.Height / 2) + RECTANGLED_DISPLAY_TOP + 2);
            try
            {
                dc.DrawImage(picBattery.Image,
                    new Rectangle(1,
                        RECTANGLED_DISPLAY_TOP + 2,
                        24, 24),
                    new Rectangle(0, 0, picBattery.Image.Width, picBattery.Image.Height),
                    GraphicsUnit.Pixel);
            }
            catch { }
            // format time-of-day to string
            str = " " + ((DateTime.Now.TimeOfDay.Hours < 10) ?
                "0" + DateTime.Now.TimeOfDay.Hours.ToString() :
                DateTime.Now.TimeOfDay.Hours.ToString()) + ":" +
                ((DateTime.Now.TimeOfDay.Minutes < 10) ?
                    "0" + DateTime.Now.TimeOfDay.Minutes.ToString() :
                    DateTime.Now.TimeOfDay.Minutes.ToString()) + " ";
            strWH = dc.MeasureString(str, todFont);
            int volR = (int)(Width - strWH.Width - 24 - 4);
            // draw a rectangle arount time of day
            dc.DrawRectangle(new Pen(SystemColors.Control, 2), (int)(Width - strWH.Width - 4 - 24),
                RECTANGLED_DISPLAY_TOP, (int)strWH.Width + 2 + 24,
                RECTANGLED_DISPLAY_HEIGHT + 2);
            // draw time of day
            dc.DrawString(str, todFont, new SolidBrush(TextColor),
               Width - strWH.Width - 3,
               (RECTANGLED_DISPLAY_HEIGHT / 2 - strWH.Height / 2) + RECTANGLED_DISPLAY_TOP + 2);
            try
            {
                dc.DrawImage(picClock.Image,
                    new Rectangle((int)(Width - strWH.Width - 3 - 24),
                        RECTANGLED_DISPLAY_TOP + 2,
                        24, 24),
                    new Rectangle(0, 0, picClock.Image.Width, picClock.Image.Height),
                    GraphicsUnit.Pixel);
            }
            catch { }
            // draw volume
            str = " " + DeviceSpecifics.Volume.ToString() + " % ";
            strWH = dc.MeasureString(str, todFont);
            volL = (int)((volR - volL) / 2 - (strWH.Width + 24 + 2) / 2) + volL;
            dc.DrawRectangle(new Pen(SystemColors.Control, 2), volL,
                RECTANGLED_DISPLAY_TOP, (int)strWH.Width + 2 + 24,
                RECTANGLED_DISPLAY_HEIGHT + 2);
            dc.DrawString(str, todFont, new SolidBrush(TextColor),
               volL +1 + 24,
               (RECTANGLED_DISPLAY_HEIGHT / 2 - strWH.Height / 2) + RECTANGLED_DISPLAY_TOP + 2);
            try
            {
                dc.DrawImage(picVol.Image,
                    new Rectangle(volL + 2,
                        RECTANGLED_DISPLAY_TOP + 2,
                        24, 24),
                    new Rectangle(0, 0, picVol.Image.Width, picVol.Image.Height),
                    GraphicsUnit.Pixel);
            }
            catch { }
        }
        // draw media info
        void DrawMediaTags(Graphics dc)
        {
            try
            {
                flyingTextCount = 0;
                // draw active book name
                DrawStringAndTestFlying(dc, Library.BookStore.ActiveBookName, 0);
                // draw album tag
                DrawStringAndTestFlying(dc, Player.GetMediaTAG(eTagNames.ALBUM), 1);
                // draw title tag if present, otherwise draw file name
                String str = Player.GetMediaTAG(eTagNames.TITLE);
                if (str.Length == 0)
                    str = Player.PlayingName;
                DrawStringAndTestFlying(dc, str, 2);
                // draw author tag
                DrawStringAndTestFlying(dc, Player.GetMediaTAG(eTagNames.AUTHOR), 3);
                // draw comment tag
                DrawStringAndTestFlying(dc, Player.GetMediaTAG(eTagNames.COMMENT), 4);
                // draw media index in the playlist and playllist media count
                DrawStringAndTestFlying(dc, (Player.PlayingIndex + 1).ToString() +
                    " / " + Player.PlaylistCount.ToString(), 5);
            }
            catch { }
        }
        // test for flying text candidates and draw
        void DrawStringAndTestFlying(Graphics dc, String str, int line)
        {
            str = (str.Replace('\n', ' ')).Replace('\r', ' ');
            SizeF strWH = dc.MeasureString(str, this.Font);
            if ((strWH.Width + FLYING_TEXT_WIDTH_THRESHOLD) > Width)
            {
                fti[flyingTextCount].line = line;
                fti[flyingTextCount].originalText = fti[flyingTextCount].flyingText =
                    FLYING_TEXT_PREFIX + str + FLYING_TEXT_SUFFIX;
                dc.DrawString(fti[flyingTextCount].flyingText,
                    this.Font, new SolidBrush(TextColor),
                    0, DISPLAY_TOP + DISPLAY_GUTTER * line);
                flyingTextCount++;
            }
            else
                DrawString(dc, str, DISPLAY_TOP + line * DISPLAY_GUTTER, strWH);
        }
        // the timeline marker and media full duration are called from either
        // the paint event or the media location changed event. 
        void DrawLocation(Graphics dc)
        {
            try
            {
                int fileDuration = Player.FileDuration(Player.PlayingIndex);
                String str = Player.LocationString + " / " + Player.DurationString +
                    ((fileDuration == -1)? "": 
                    (Math.Abs(fileDuration - Player.Duration) > 1)? "  -" : "  +");
                DrawString(dc, str, DISPLAY_TOP + 6 * DISPLAY_GUTTER,
                    dc.MeasureString(str, this.Font));
            }
            catch { }
        }
        // function also called from several places
        void DrawStatus(Graphics dc, String status)
        {
            SizeF strWH = dc.MeasureString(status, this.Font);
            dc.DrawString(status, this.Font, new SolidBrush(TextColor),
                this.Width / 2 - strWH.Width / 2, 
                DISPLAY_TOP + DISPLAY_GUTTER * 7 + 
                (RECTANGLED_DISPLAY_HEIGHT / 2 - strWH.Height / 2) + 7);
            dc.DrawRectangle(new Pen(SystemColors.Control, 2),
                (int)(this.Width / 2 - strWH.Width / 2 - 8), DISPLAY_TOP + DISPLAY_GUTTER * 7 + 5,
                (int)(strWH.Width + 14), RECTANGLED_DISPLAY_HEIGHT + 2);
        }
        // this function calculates the size of the display and positions 
        // it in the horizontal middle
        void DrawString(Graphics dc, String str, int h, SizeF strWH)
        {
                dc.DrawString(str, this.Font, new SolidBrush(TextColor),
                    this.Width / 2 - strWH.Width / 2, h);
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Israel Israel
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions