/*
Copyright 2009, Alvaro J. Iradier
This file is part of xPressent (Windows Mobile Remote).
xPressent is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
xPressent is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with xPressent. If not, see .
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
namespace xpressent_remote
{
public class TextPictureBox: Control
{
Bitmap offscreen = null;
Bitmap image, darkImage;
Bitmap notesBitmap;
Icon prevBitmap, nextBitmap;
string notes = "";
int textSize = 11;
int notesOffset;
int lastMousePos;
bool showNotes;
bool dragging = false;
bool dragged = false;
public delegate void NextPrevEventDelegate();
public event NextPrevEventDelegate NextEvent;
public event NextPrevEventDelegate PrevEvent;
public Bitmap Image
{
get { return this.image; }
set {
this.image = value;
if (value != null)
{
this.darkImage = AdjustBrightness(this.Image, 20);
}
else
{
this.darkImage = null;
}
DrawOffscreen();
this.Invalidate();
}
}
public new string Text
{
get { return this.notes; }
set
{
this.notes = value.Replace("\r", "");
this.notesOffset = 0;
DrawNotes();
DrawOffscreen();
this.Invalidate();
}
}
public bool ShowNotes
{
get { return this.showNotes; }
set {
this.showNotes = value;
DrawNotes();
DrawOffscreen();
this.Refresh();
}
}
public int TextSize
{
get { return this.textSize; }
set {
if (value < 1) return;
this.textSize = value;
DrawNotes();
DrawOffscreen();
this.Refresh();
}
}
private struct PixelData
{
public byte Blue;
public byte Green;
public byte Red;
}
public TextPictureBox()
: base()
{
this.InitializeComponent();
}
private string[] splitLines(Graphics g, Font f, Font ff, string text, int maxwidth, out int height)
{
bool fixed_mode = false;
List lines = new List();
height = 0;
foreach (string line in text.Split('\n'))
{
if (fixed_mode)
{
if (line.CompareTo("}") == 0)
{
fixed_mode = false;
lines.Add(line);
continue;
}
lines.Add(line);
height += (int)g.MeasureString(line, ff).Height;
}
else
{
if (line.CompareTo("{") == 0)
{
fixed_mode = true;
lines.Add(line);
continue;
}
string current_line = "";
foreach (string word in line.Split(' '))
{
SizeF size = g.MeasureString(current_line + word, f);
if (size.Width > maxwidth)
{
string prev_line = current_line;
lines.Add(current_line);
height += (int)g.MeasureString(current_line, f).Height;
current_line = "";
for (int i = 0; i < prev_line.Length; i++)
{
if (prev_line[i] == ' ' || prev_line[i] == '-' || prev_line[i] == '*')
{
current_line += " ";
}
else
{
break;
}
}
}
current_line += word + " ";
}
lines.Add(current_line);
height += (int)g.MeasureString(current_line, f).Height;
}
}
return lines.ToArray();
}
private void DrawNotes()
{
Graphics g = this.CreateGraphics();
Font font = new Font(FontFamily.GenericSansSerif, this.textSize, 0);
Font fixed_font = new Font(FontFamily.GenericMonospace, this.textSize, 0);
int total_height = 0;
string[] textLines = splitLines(g, font, fixed_font, this.notes ?? "", this.Width - 10, out total_height);
if (this.notesBitmap != null) this.notesBitmap.Dispose();
this.notesBitmap = new Bitmap(this.Width - 10, total_height);
g.Dispose();
Graphics g2 = Graphics.FromImage(this.notesBitmap);
float y = 0;
bool fixed_mode = false;
foreach (string line in textLines)
{
if (fixed_mode)
{
if (line.CompareTo("}") == 0)
{
fixed_mode = false;
continue;
}
g2.DrawString(line, fixed_font, new SolidBrush(Color.White), 0, y);
y += g2.MeasureString(line, fixed_font).Height;
}
else
{
if (line.CompareTo("{") == 0)
{
fixed_mode = true;
continue;
}
g2.DrawString(line, font, new SolidBrush(Color.White), 0, y);
y += g2.MeasureString(line, font).Height;
}
}
g2.Dispose();
}
private void DrawOffscreen()
{
if (this.offscreen == null)
{
this.offscreen = new Bitmap(this.Width, this.Height);
}
Bitmap off = this.offscreen;
Graphics g = Graphics.FromImage(off);
g.FillRectangle(new SolidBrush(Color.Black), 0,0, off.Width, off.Height);
if (this.showNotes)
{
if (this.darkImage != null)
{
g.DrawImage(this.darkImage,
(off.Width - this.darkImage.Width) / 2,
(off.Height - this.darkImage.Height) / 2);
}
if (this.notesBitmap == null)
{
DrawNotes();
}
ImageAttributes attr = new ImageAttributes();
attr.SetColorKey(Color.Black, Color.Black);
g.DrawImage(this.notesBitmap,
new Rectangle(5,5 + this.notesOffset, this.notesBitmap.Width, this.notesBitmap.Height),
0, 0, this.notesBitmap.Width, this.notesBitmap.Height, GraphicsUnit.Pixel,attr);
}
else
{
if (this.image != null)
{
g.DrawImage(this.image,
(off.Width - this.image.Width) / 2,
(off.Height - this.image.Height) / 2);
}
}
g.DrawIcon(this.prevBitmap, 0, this.Height - this.prevBitmap.Height);
g.DrawIcon(this.nextBitmap, this.Width - this.nextBitmap.Width, this.Height - this.nextBitmap.Height);
}
protected override void OnPaint(PaintEventArgs e)
{
if (this.offscreen == null) DrawOffscreen();
e.Graphics.DrawImage(this.offscreen, 0, 0);
}
protected override void OnPaintBackground(PaintEventArgs e)
{
}
private static unsafe Bitmap AdjustBrightness(Bitmap Bitmap, decimal Percent)
{
Percent /= 100;
Bitmap Snapshot = (Bitmap)Bitmap.Clone();
Rectangle rect = new Rectangle(0, 0, Bitmap.Width, Bitmap.Height);
BitmapData BitmapBase = Snapshot.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
byte* BitmapBaseByte = (byte*)BitmapBase.Scan0.ToPointer();
// the number of bytes in each row of a bitmap is allocated (internally) to be equally divisible by 4
int RowByteWidth = rect.Width * 3;
if (RowByteWidth % 4 != 0)
{
RowByteWidth += (4 - (RowByteWidth % 4));
}
for (int i = 0; i < RowByteWidth * rect.Height; i += 3)
{
PixelData* p = (PixelData*)(BitmapBaseByte + i);
p->Red = (byte)Math.Round(Math.Min(p->Red * Percent, (decimal)255));
p->Green = (byte)Math.Round(Math.Min(p->Green * Percent, (decimal)255));
p->Blue = (byte)Math.Round(Math.Min(p->Blue * Percent, (decimal)255));
}
Snapshot.UnlockBits(BitmapBase);
return Snapshot;
}
private void InitializeComponent()
{
this.SuspendLayout();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TextPictureBox));
prevBitmap = (Icon)resources.GetObject("left_arrow_icon");
nextBitmap = (Icon)resources.GetObject("right_arrow_icon");
//
// TextPictureBox
//
this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.TextPictureBox_MouseMove);
this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.TextPictureBox_MouseDown);
this.Resize += new System.EventHandler(this.TextPictureBox_Resize);
this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.TextPictureBox_MouseUp);
this.ResumeLayout(false);
}
private void TextPictureBox_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left && !this.dragged)
{
this.dragging = true;
this.lastMousePos = e.Y;
}
else
{
this.dragging = false;
}
}
private void TextPictureBox_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
this.dragging = false;
this.lastMousePos = -1;
if (!this.dragged)
{
if (e.Y >= (this.Height - this.prevBitmap.Height) &&
e.X <= this.prevBitmap.Width)
{
if (this.PrevEvent != null) this.PrevEvent();
}
else if (e.Y >= (this.Height - this.nextBitmap.Height) &&
e.X >= this.Width - this.nextBitmap.Width)
{
if (this.NextEvent != null) this.NextEvent();
}
else
{
this.ShowNotes = !this.ShowNotes;
}
}
}
this.dragged = false;
}
private void TextPictureBox_MouseMove(object sender, MouseEventArgs e)
{
if (this.dragging && (e.Y < this.lastMousePos - 3 || e.Y > this.lastMousePos + 3))
{
this.dragged = true;
}
if (this.dragging && this.dragged)
{
if (!this.showNotes || this.notesBitmap == null) return;
this.notesOffset += e.Y - this.lastMousePos;
if (notesOffset > 0) this.notesOffset = 0;
if (notesOffset < 0 - this.notesBitmap.Height) notesOffset = 0 - this.notesBitmap.Height;
this.lastMousePos = e.Y;
DrawOffscreen();
this.Refresh();
}
}
private void TextPictureBox_Resize(object sender, EventArgs e)
{
if (this.offscreen != null)
{
this.offscreen.Dispose();
this.offscreen = null;
}
this.DrawNotes();
this.DrawOffscreen();
this.Invalidate();
}
}
}