private void DrawTiles(IGraphicsContext context, int tileSize, float realScrollBarHeight) { float deltaZoom = (float) (Zoom/Math.Floor(Zoom)); int startDirtyTile = (int)Math.Floor((ContentOffset.X + context.DirtyRect.X) / ((float)tileSize * deltaZoom)); int numberOfDirtyTilesToDraw = (int)Math.Ceiling(context.DirtyRect.Width / tileSize) + 1; var request = new WaveFormBitmapRequest() { StartTile = startDirtyTile, EndTile = startDirtyTile + numberOfDirtyTilesToDraw, TileSize = tileSize, BoundsWaveForm = Frame, Zoom = _zoom, DisplayType = _displayType }; var tiles = _waveFormCacheService.GetTiles(request); //Console.WriteLine("WaveFormControl - #### startTile: {0} startTileX: {1} contentOffset.X: {2} contentOffset.X/tileSize: {3} numberOfTilesToFillWidth: {4} firstTileX: {5}", startTile, startTile * tileSize, ContentOffset.X, ContentOffset.X / tileSize, numberOfTilesToFillWidth, (startTile * tileSize) - ContentOffset.X); foreach (var tile in tiles) { float tileDeltaZoom = Zoom / tile.Zoom; float x = tile.ContentOffset.X * tileDeltaZoom; float tileWidth = tileSize * tileDeltaZoom; float tileHeight = (ShowScrollBar && Zoom > 1) ? Frame.Height - realScrollBarHeight : Frame.Height; //Console.WriteLine("WaveFormControl - Draw - tile - x: {0} tileWidth: {1} deltaZoom: {2}", x, tileWidth, deltaZoom); //Console.WriteLine("WaveFormControl - Draw - tile - tile.ContentOffset.X: {0} x: {1} tileWidth: {2} tile.Zoom: {3}", tile.ContentOffset.X, x, tileWidth, tile.Zoom); //context.DrawImage(new BasicRectangle(x - ContentOffset.X, 0, tileWidth, Frame.Height), tile.Image.ImageSize, tile.Image.Image); context.DrawImage(new BasicRectangle(x - ContentOffset.X, 0, tileWidth, tileHeight), tile.Image.ImageSize, tile.Image.Image); // Debug overlay //context.DrawRectangle(new BasicRectangle(x - ContentOffset.X, 0, tileWidth, Frame.Height), new BasicBrush(new BasicColor(0, 0, 255, 50)), _penCursorLine); //context.DrawText(string.Format("{0:0.0}", tile.Zoom), new BasicPoint(x - ContentOffset.X + 2, 4), _textColor, "Roboto", 11); } }
private void DrawScrollBar(IGraphicsContext context, int tileSize, float realScrollBarHeight) { if (ShowScrollBar && Zoom > 1) { int startTile = 0; int numberOfTilesToFillWidth = (int)Math.Ceiling(Frame.Width / tileSize);// + 1; // maybe a bug here? when one of the tile is partially drawn, you need another one? var requestScrollBar = new WaveFormBitmapRequest() { StartTile = startTile, EndTile = numberOfTilesToFillWidth, TileSize = tileSize, BoundsWaveForm = new BasicRectangle(0, 0, Frame.Width, ScrollBarHeight), // Frame Zoom = 1, IsScrollBar = true, DisplayType = _displayType }; // TODO: Cache those tiles, we do not need to request them continually since these tiles are always at 100% var tilesScrollBar = _waveFormCacheService.GetTiles(requestScrollBar); foreach (var tile in tilesScrollBar) { context.DrawImage(new BasicRectangle(tile.ContentOffset.X, Frame.Height - realScrollBarHeight, tileSize, realScrollBarHeight), tile.Image.ImageSize, tile.Image.Image); } // Draw a veil over the area that's not visible. The veil alpha gets stronger as the zoom progresses. byte startAlpha = 170; byte maxAlpha = 210; byte alpha = (byte)Math.Min(maxAlpha, (startAlpha + (60 * (Zoom / 10)))); var colorVisibleArea = new BasicColor(32, 40, 46, alpha); float visibleAreaWidth = (1 / Zoom) * Frame.Width; float visibleAreaX = (1 / Zoom) * ContentOffset.X; var rectLeftArea = new BasicRectangle(0, Frame.Height - realScrollBarHeight, visibleAreaX, realScrollBarHeight); var rectRightArea = new BasicRectangle(visibleAreaX + visibleAreaWidth, Frame.Height - realScrollBarHeight, Frame.Width - visibleAreaX - visibleAreaWidth, realScrollBarHeight); //context.DrawRectangle(new BasicRectangle(visibleAreaX, Frame.Height - scrollBarHeight, visibleAreaWidth, scrollBarHeight), new BasicBrush(colorVisibleArea), new BasicPen()); context.DrawRectangle(rectLeftArea, new BasicBrush(colorVisibleArea), new BasicPen()); context.DrawRectangle(rectRightArea, new BasicBrush(colorVisibleArea), new BasicPen()); } }
private void DrawAlbumCoverZone(IGraphicsContext context, int row, AudioFile audioFile2, DrawCellState state) { var pen = new BasicPen(); var penTransparent = new BasicPen(); var brushGradient = new BasicGradientBrush(); var item = _items[row]; //string albumTitle = audioFile != null ? audioFile.AlbumTitle : state.CurrentAlbumTitle; // if this is an empty row, keep last album title // Check for an album title change (or the last item of the grid) if (state.CurrentAlbumArtKey == item.AlbumArtKey) return; state.CurrentAlbumArtKey = item.AlbumArtKey; int albumCoverStartIndex = 0; int albumCoverEndIndex = 0; // For displaying the album cover, we need to know how many songs of the same album are bundled together // Start by getting the start index for (int c = row; c > 0; c--) { var previousItem = _items[c]; if (previousItem.AlbumArtKey != item.AlbumArtKey) { albumCoverStartIndex = c + 1; break; } } // Find the end index for (int c = row + 1; c < _items.Count; c++) { var nextItem = _items[c]; // If the album title is different, this means we found the next album title if (nextItem.AlbumArtKey != item.AlbumArtKey) { albumCoverEndIndex = c - 1; break; } // If this is the last item of the grid... else if (c == _items.Count - 1) { albumCoverEndIndex = c; break; } } var audioFile = _items[albumCoverStartIndex].AudioFile; // Calculate y and height int scrollbarOffsetY = (_startLineNumber * _songCache.LineHeight) - VerticalScrollBar.Value; int y = ((albumCoverStartIndex - _startLineNumber) * _songCache.LineHeight) + _songCache.LineHeight + scrollbarOffsetY; // Calculate the height of the album cover zone (+1 on end index because the array is zero-based) int linesToCover = Math.Min(MinimumRowsPerAlbum, (albumCoverEndIndex + 1 - albumCoverStartIndex)); int albumCoverZoneHeight = linesToCover * _songCache.LineHeight; int heightWithPadding = Math.Min(albumCoverZoneHeight - (_theme.Padding * 2), _songCache.ActiveColumns[0].Width - (_theme.Padding * 2)); // Make sure the height is at least zero (not necessary to draw anything!) if (albumCoverZoneHeight > 0) { // Draw album cover background var rectAlbumCover = new BasicRectangle(0 - HorizontalScrollBar.Value, y, _songCache.ActiveColumns[0].Width, albumCoverZoneHeight); brushGradient = new BasicGradientBrush(_theme.AlbumCoverBackgroundColor, _theme.AlbumCoverBackgroundColor, 90); context.DrawRectangle(rectAlbumCover, brushGradient, penTransparent); // Measure available width for text int widthAvailableForText = _columns[0].Width - (_theme.Padding * 2); // Display titles depending on if an album art was found var rectAlbumCoverArt = new BasicRectangle(); var rectAlbumTitleText = new BasicRectangle(); var rectArtistNameText = new BasicRectangle(); var sizeAlbumTitle = new BasicRectangle(); var sizeArtistName = new BasicRectangle(); bool useAlbumArtOverlay = false; bool displayArtistNameAndAlbumTitle = false; // Try to extract image from cache IBasicImage imageAlbumCover = null; SongGridViewImageCache cachedImage = null; try { cachedImage = _imageCache.FirstOrDefault(x => x.Key == item.AlbumArtKey); } catch (Exception ex) { Tracing.Log(ex); } if (cachedImage != null) imageAlbumCover = cachedImage.Image; // Album art not found in cache; try to find an album cover in one of the file if (cachedImage == null) { try { // Check if the album cover is already in the pile bool albumCoverFound = false; foreach (var arg in _workerUpdateAlbumArtPile) { // Match by file path if (arg.AudioFile.FilePath.ToUpper() == audioFile.FilePath.ToUpper()) { albumCoverFound = true; } } // Add to the pile only if the album cover isn't already in it if (!albumCoverFound) { // Add item to update album art worker pile var arg = new SongGridViewBackgroundWorkerArgument(); arg.AudioFile = audioFile; arg.LineIndex = row; arg.RectAlbumArt = new BasicRectangle(0, 0, heightWithPadding, heightWithPadding); _workerUpdateAlbumArtPile.Add(arg); } } catch(Exception ex) { Console.WriteLine("SongGridViewControl - Failed to load cache image: {0}" , ex); } } // There are at least two lines; is there an album cover to display? if (imageAlbumCover == null) { // There is no album cover to display; display only text. // Set string format //stringFormat.Alignment = StringAlignment.Center; //stringFormat.Trimming = StringTrimming.EllipsisWord; sizeArtistName = context.MeasureText(audioFile.ArtistName, new BasicRectangle(0, 0, widthAvailableForText, heightWithPadding), _theme.FontNameAlbumArtTitle, _theme.FontSize + 2); sizeAlbumTitle = context.MeasureText(audioFile.AlbumTitle, new BasicRectangle(0, 0, widthAvailableForText, heightWithPadding), _theme.FontNameAlbumArtSubtitle, _theme.FontSize); // Display the album title at the top of the zome rectArtistNameText = new BasicRectangle(_theme.Padding - HorizontalScrollBar.Value, y + _theme.Padding, widthAvailableForText, heightWithPadding); rectAlbumTitleText = new BasicRectangle(_theme.Padding - HorizontalScrollBar.Value, y + _theme.Padding + sizeArtistName.Height, widthAvailableForText, heightWithPadding); displayArtistNameAndAlbumTitle = true; useAlbumArtOverlay = true; } else { // There is an album cover to display with more than 2 lines. // Set string format //stringFormat.Alignment = StringAlignment.Near; //stringFormat.Trimming = StringTrimming.EllipsisWord; float widthRemainingForText = _columns[0].Width - (_theme.Padding * 3) - heightWithPadding; sizeArtistName = context.MeasureText(audioFile.ArtistName, new BasicRectangle(0, 0, widthRemainingForText, heightWithPadding), _theme.FontNameAlbumArtTitle, _theme.FontSize + 2); sizeAlbumTitle = context.MeasureText(audioFile.AlbumTitle, new BasicRectangle(0, 0, widthRemainingForText, heightWithPadding), _theme.FontNameAlbumArtSubtitle, _theme.FontSize); // Try to center the cover art + padding + max text width //float maxWidth = Math.Max(sizeArtistName.Width, sizeAlbumTitle.Width); float albumCoverX = _theme.Padding - 2; // (_columns[0].Width - heightWithPadding - _theme.Padding - _theme.Padding - maxWidth) / 2; float artistNameY = _theme.Padding + 1; // (albumCoverZoneHeight - sizeArtistName.Height - sizeAlbumTitle.Height) / 2; // Display the album title at the top of the zome rectArtistNameText = new BasicRectangle(albumCoverX + heightWithPadding + _theme.Padding - HorizontalScrollBar.Value, y + artistNameY, widthRemainingForText, heightWithPadding); rectAlbumTitleText = new BasicRectangle(albumCoverX + heightWithPadding + _theme.Padding - HorizontalScrollBar.Value, y + artistNameY + sizeArtistName.Height + (_theme.Padding / 8f), widthRemainingForText, heightWithPadding); rectAlbumCoverArt = new BasicRectangle(albumCoverX - HorizontalScrollBar.Value, y + _theme.Padding, heightWithPadding, heightWithPadding); displayArtistNameAndAlbumTitle = widthRemainingForText > 20; useAlbumArtOverlay = true; } // Display album cover if (imageAlbumCover != null) context.DrawImage(rectAlbumCoverArt, new BasicRectangle(0, 0, imageAlbumCover.ImageSize.Width, imageAlbumCover.ImageSize.Height), imageAlbumCover.Image); //context.DrawImage(rectAlbumCoverArt, new BasicRectangle(0, 0, rectAlbumCoverArt.Width, rectAlbumCoverArt.Height), imageAlbumCover.Image); // if (useAlbumArtOverlay) // { // // Draw artist name and album title background // var rectArtistNameBackground = new BasicRectangle(rectArtistNameText.X - (_theme.Padding / 2), rectArtistNameText.Y - (_theme.Padding / 4), sizeArtistName.Width + _theme.Padding, sizeArtistName.Height + (_theme.Padding / 2)); // var rectAlbumTitleBackground = new BasicRectangle(rectAlbumTitleText.X - (_theme.Padding / 2), rectAlbumTitleText.Y - (_theme.Padding / 4), sizeAlbumTitle.Width + _theme.Padding, sizeAlbumTitle.Height + (_theme.Padding / 2)); // var brushTextBackground = new BasicBrush(new BasicColor(0, 0, 0, 30)); // context.DrawRectangle(rectArtistNameBackground, brushTextBackground, penTransparent); // context.DrawRectangle(rectAlbumTitleBackground, brushTextBackground, penTransparent); // } if (displayArtistNameAndAlbumTitle) { context.DrawText(audioFile.ArtistName, rectArtistNameText, _theme.HeaderTextColor, _theme.FontNameAlbumArtTitle, _theme.FontSize + 2); context.DrawText(audioFile.AlbumTitle, rectAlbumTitleText, _theme.HeaderTextColor, _theme.FontNameAlbumArtSubtitle, _theme.FontSize); } // Draw horizontal line to distinguish albums // Part 1: Draw line over grid pen = new BasicPen(new BasicBrush(new BasicColor(180, 180, 180)), 1); context.DrawLine(new BasicPoint(_columns[0].Width, y), new BasicPoint(Frame.Width, y), pen); // Part 2: Draw line over album art zone, in a lighter color pen = new BasicPen(new BasicBrush(new BasicColor(115, 115, 115)), 1); context.DrawLine(new BasicPoint(0, y), new BasicPoint(_columns[0].Width, y), pen); } }