/// <summary> /// Create a QsosWFBox object based on an XmlNode for it from an /// XQSL file /// </summary> /// <param name="card">The CardWF object that will contain the text item</param> /// <param name="node">XmlNode object that contains the data for the text item</param> /// <param name="culture">CultureInfo object that describes the culture /// that the XQSL file was saved with</param> /// <returns></returns> private static QsosWFBox CreateQsosBox(CardWF card, XmlNode node, CultureInfo culture) { QsosWFBox qBox = new QsosWFBox(); qBox.QslCard = card; qBox.FontSize = 12.0F * FontScaleFactor; XmlNode qNode = XmlProcs.GetFirstChildElement(node); while(qNode != null) { XmlText text = XmlProcs.GetTextNode(qNode); switch(qNode.Name) { case "QsoBoxBase": qNode = XmlProcs.GetFirstChildElement(qNode); break; case "CardItem": GetCardItemData(qBox, qNode, culture); break; case "ShowManager": if(text != null) { qBox.ShowManager = text.Value=="true" ? true : false; } break; case "ShowFrequency": if(text != null) { qBox.ShowFrequency = text.Value=="true" ? true : false; } break; case "ShowPseTnx": if(text != null) { qBox.ShowPseTnx = text.Value=="true" ? true : false; } break; case "MaximumQsos": if(text != null) { qBox.MaximumQsos = Int32.Parse(text.Value, culture); } break; case "DateFormat": if(text != null) { qBox.DateFormat = text.Value; } break; case "LineTextBrush": qBox.LineTextColor = XmlProcs.ConvertXmlToColor(qNode, culture); break; case "CallsignBrush": qBox.CallsignColor = XmlProcs.ConvertXmlToColor(qNode, culture); break; case "ManagerBrush": qBox.ManagerColor = XmlProcs.ConvertXmlToColor(qNode, culture); break; case "FaceName": if(text != null) { qBox.FontName = GetValidFont(text.Value); } break; case "BackgroundBrush": qBox.BackgroundColor = XmlProcs.ConvertXmlToColor(qNode, culture); break; case "BackgroundOpacity": if(text != null) { float value = 0F; if(!float.TryParse(text.Value, NumberStyles.Float, culture, out value)) { if(!float.TryParse(text.Value, NumberStyles.Float, CultureInfo.InvariantCulture, out value)) { XmlException ex = new XmlException( "Bad QsosBox property value in card file." + Environment.NewLine + "Did you modify the card file by hand?"); ex.Data.Add("Property", "BackgroundOpacity"); ex.Data.Add("Value", text.Value); App.Logger.Log(ex); } } qBox.BackgroundOpacity = value; } break; case "ConfirmingMultiText": CountMacro cMacro = new CountMacro(); StaticText designText = new StaticText(); designText.Text = ((App)App.Current).UserPreferences. ConfirmingText.GetText(card, null, true); cMacro.DesignText.Clear(); cMacro.DesignText.Add(designText); StaticText falseText = new StaticText(); string fText = text.Value; if(!fText.EndsWith(" ")) { fText += " "; } falseText.Text = fText; cMacro.FalseText.Clear(); cMacro.FalseText.Add(falseText); qBox.ConfirmingText.Clear(); qBox.ConfirmingText.Add(cMacro); break; case "Confirming1Text": // code assumes that Confirming1Text occurs // after ConfirmingMultiText in the // xqsl file. This matches the save order in // QslDesignAndPrint. StaticText trueText = new StaticText(); string tText = text.Value; if(!tText.EndsWith(" ")) { tText += " "; } trueText.Text = tText; CountMacro countMacro = qBox.ConfirmingText[0] as CountMacro; countMacro.TrueText.Clear(); countMacro.TrueText.Add(trueText); break; case "ViaText": if(text != null) { qBox.ViaText = text.Value; } break; case "YYYYMMDDText": if(text != null) { qBox.YYYYMMDDText = text.Value; } break; case "DDMMMYYText": if(text != null) { qBox.DDMMMYYText = text.Value; } break; case "DDMMYYText": if(text != null) { qBox.DDMMYYText = text.Value; } break; case "TimeText": if(text != null) { qBox.TimeText = text.Value; } break; case "ModeText": if(text != null) { qBox.ModeText = text.Value; } break; case "BandText": if(text != null) { qBox.BandText = text.Value; } break; case "FrequencyText": if(text != null) { qBox.FreqText = text.Value; } break; case "RSTText": if(text != null) { qBox.RSTText = text.Value; } break; case "QSLText": if(text != null) { qBox.QSLText = text.Value; } break; case "PseText": if(text != null) { qBox.PseText = text.Value; } break; case "TnxText": if(text != null) { qBox.TnxText = text.Value; } break; } qNode = XmlProcs.GetNextSiblingElement(qNode); } return qBox; }
/// <summary> /// Fill the Qsos Box background with QsosBox.BackgroundBrush at the /// opacity of QsosBox.BackgroundOpacity /// </summary> /// <param name="g">Graphics object on which to draw the background</param> /// <param name="boxOutline">GraphicsPath object describing the outline /// of the Qsos box</param> /// <param name="box">Qsos box object </param> private void FillQsosBoxBackground(Graphics g, GraphicsPath boxOutline, QsosWFBox box) { // To set the opacity, we must first create a bitmap containing the // background at 100% opacity, then draw that on the final Graphics object // at the required opacity. Bitmap bitmap = new Bitmap(CardLocation.X + box.X + box.Width, CardLocation.Y + box.Y + box.Height); Graphics bGraphics = Graphics.FromImage(bitmap); bGraphics.FillPath(box.BackgroundBrush, boxOutline); // Create a color matrix that is partially opaque float[][] matrixItems ={ new float[] {1, 0, 0, 0, 0}, new float[] {0, 1, 0, 0, 0}, new float[] {0, 0, 1, 0, 0}, new float[] {0, 0, 0, (float)box.BackgroundOpacity, 0}, new float[] {0, 0, 0, 0, 1}}; ColorMatrix colorMatrix = new ColorMatrix(matrixItems); // Create an ImageAttributes object and set its color matrix. ImageAttributes imageAttrs = new ImageAttributes(); imageAttrs.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); g.DrawImage(bitmap, new Rectangle(CardLocation.X + box.X, CardLocation.Y + box.Y, box.Width, box.Height), CardLocation.X + box.X, CardLocation.Y + box.Y, box.Width, box.Height, GraphicsUnit.Pixel, imageAttrs); bGraphics.Dispose(); bitmap.Dispose(); }
/// <summary> /// Create a QsosWFBox that is a deep copy of this one /// </summary> /// <returns>QsosWFBox object that is a deep copy of this one</returns> public QsosWFBox Clone() { QsosWFBox box = new QsosWFBox(true); box.CopyBaseProperties(this); box.ShowManager = this.ShowManager; box.ShowFrequency = this.ShowFrequency; box.ShowPseTnx = this.ShowPseTnx; box.MaximumQsos = this.MaximumQsos; box.DateFormat = this.DateFormat; box.LineTextColor = this.LineTextColor; box.CallsignColor = this.CallsignColor; box.ManagerColor = this.ManagerColor; box.FontSize = this.FontSize; box.FontName = this.FontName; box.BackgroundColor = this.BackgroundColor; box.BackgroundOpacity = this.BackgroundOpacity; box.ConfirmingText.Clear(); foreach(TextPart part in this.ConfirmingText) { box.ConfirmingText.Add(part.Clone()); } box.ViaText = this.ViaText; box.YYYYMMDDText = this.YYYYMMDDText; box.DDMMMYYText = this.DDMMMYYText; box.DDMMYYText = this.DDMMYYText; box.TimeText = this.TimeText; box.ModeText = this.ModeText; box.BandText = this.BandText; box.FreqText = this.FreqText; box.RSTText = this.RSTText; box.QSLText = this.QSLText; box.PseText = this.PseText; box.TnxText = this.TnxText; return box; }
/// <summary> /// Draw the header text for the Qsos box /// </summary> /// <param name="g">Graphics object on which to draw the text</param> /// <param name="font">Font to draw the text in</param> /// <param name="colHeaders">List of headers to draw</param> /// <param name="colWidths">List of widths for the columns</param> /// <param name="box">Qsos box object which is being drawn</param> private void DrawHeaders(Graphics g, Font font, List<string> colHeaders, List<float> colWidths, QsosWFBox box) { SizeF size = g.MeasureString(colHeaders[0], font); float colPosition = CardLocation.X + box.X; float textY = (float)(CardLocation.Y + box.Y + size.Height + 3 + 2); for(int col = 0; col < colWidths.Count; col++) { if(colWidths[col] > 0) { size = g.MeasureString(colHeaders[col], font); float startX = colPosition + (colWidths[col] - size.Width) / 2; g.DrawString(colHeaders[col], font, box.LineTextBrush, startX, textY); } colPosition += colWidths[col]; } }
/// <summary> /// Draw the QSO information onto the Qsos Box /// </summary> /// <param name="g">Graphics object on which to draw the QSO information</param> /// <param name="qsos">QSOs to draw</param> /// <param name="font">Font to use to draw the QSO information</param> /// <param name="colWidths">List of column widths in the QSOs Box</param> /// <param name="box">QsosWFBox object that is being drawn</param> private void DrawQsos(Graphics g, List<DispQso> qsos, Font font, List<float> colWidths, QsosWFBox box) { if(qsos != null) { SizeF size = g.MeasureString("X", font); float y = CardLocation.Y + box.Y + 2 * (size.Height + 3) + 1; foreach(DispQso qso in qsos) { float xStart = CardLocation.X + box.X; string date = GenerateDateText(qso.Date, box.DateFormat); xStart = PrintQsoDataColumnAndAdjustToNextStartColumn( g, date, font, box.LineTextBrush, colWidths[0], xStart, y); xStart = PrintQsoDataColumnAndAdjustToNextStartColumn( g, qso.Time, font, box.LineTextBrush, colWidths[1], xStart, y); xStart = PrintQsoDataColumnAndAdjustToNextStartColumn( g, qso.Band, font, box.LineTextBrush, colWidths[2], xStart, y); string freq = qso.Frequency != string.Empty ? qso.Frequency : bandFreqs[qso.Band]; xStart = PrintQsoDataColumnAndAdjustToNextStartColumn( g, freq, font, box.LineTextBrush, colWidths[3], xStart, y); string mode = qso.Submode.Equals(string.Empty) ? qso.Mode : qso.Submode; xStart = PrintQsoDataColumnAndAdjustToNextStartColumn( g, mode, font, box.LineTextBrush, colWidths[4], xStart, y); xStart = PrintQsoDataColumnAndAdjustToNextStartColumn( g, qso.RST, font, box.LineTextBrush, colWidths[5], xStart, y); string qsl = string.Empty; if(qso.Qsl.Equals("No") || qso.Qsl.Equals("Requested") || qso.Qsl.Equals(string.Empty)) { qsl = box.PseText; } else { qsl = box.TnxText; } xStart = PrintQsoDataColumnAndAdjustToNextStartColumn( g, qsl, font, box.LineTextBrush, colWidths[6], xStart, y); y += (int)size.Height + 3; } } }
/// <summary> /// Create a Graphics path object for the outside of the QSOs Box /// </summary> /// <param name="box">Qsos Box that we are drawing</param> /// <returns>GraphicsPath object describing the outside of the Qsos Box</returns> private GraphicsPath CreateOutsideBoxPath(QsosWFBox box) { GraphicsPath path = new GraphicsPath(); int left = CardLocation.X + box.X; int top = CardLocation.Y + box.Y; int right = left + box.Width; int bottom = top + box.Height; path.AddArc(left, top, 2 * boxRoundX, 2 * boxRoundY, 180, 90); path.AddLine(left + boxRoundX, top, right - boxRoundX, top); path.AddArc(right - 2 * boxRoundX, top, 2 * boxRoundX, 2 * boxRoundY, -90, 90); path.AddLine(right, top + boxRoundY, right, bottom -boxRoundY); path.AddArc(right - 2 * boxRoundX, bottom - 2 * boxRoundY, 2 * boxRoundX, 2 * boxRoundY, 0, 90); path.AddLine(right - boxRoundX, bottom, left + boxRoundX, bottom); path.AddArc(left , bottom - 2 * boxRoundY, 2 * boxRoundX, 2 * boxRoundY, 90, 90); path.AddLine(left, bottom - boxRoundY, left, top + boxRoundY); return path; }
/// <summary> /// Draw Qsos box confirming text /// </summary> /// <param name="g">Graphics object of which to draw the text</param> /// <param name="font">Font in which to draw the text</param> /// <param name="box">Qsos box being drawn</param> /// <param name="fontAdjustmentFactor">amount to adjust font sizes by. This should be /// 1 except for images where it should be 96F/resolution</param> private void DrawConfirmingText(Graphics g, Font font, List<DispQso> qsos, QsosWFBox box, float fontAdjustmentFactor) { int startX = CardLocation.X + box.X + 5; int y = CardLocation.Y + box.Y + 1; string confText = box.ConfirmingText.GetText(QslCard, qsos, QslCard.IsInDesignMode); g.DrawString(confText, font, box.LineTextBrush, startX, y); if(box.QslCard.IsInDesignMode || qsos.Count != 0) { SizeF size = g.MeasureString(confText, font); startX += (int)size.Width + 2; float fontSize = box.FontSize * fontAdjustmentFactor; y++; // compensate for bold Font callFont = new Font(box.FontName, fontSize, FontStyle.Bold, GraphicsUnit.Point); g.DrawString(Callsign, callFont, box.CallsignBrush, startX, y); if(box.ShowManager && !Manager.Equals(string.Empty)) { size = g.MeasureString(Callsign, callFont); startX += (int)size.Width; g.DrawString(box.ViaText + " " + Manager, callFont, box.ManagerBrush, startX, y); } } }
/// <summary> /// Add the row and column lines to the already created outline of the Qsos box /// </summary> /// <param name="g">Graphics object that the card is being drawn on</param> /// <param name="path">Graphics path containing the outline of the Qsos box</param> /// <param name="font">Font that text in the Qsos box is drawn in</param> /// <param name="colHeaders">Header text for the columns in the Qsos box</param> /// <param name="colWidths">Width of each column in the Qsos box</param> /// <param name="box">Qsos box being dreawn</param> private void CreateInsideBoxPath(Graphics g, ref GraphicsPath path, Font font, List<string> colHeaders, List<float> colWidths, QsosWFBox box) { int left = CardLocation.X + box.X; int top = CardLocation.Y + box.Y; int right = left + box.Width; int bottom = top + box.Height; System.Drawing.SizeF size = g.MeasureString("SampleText", font); int lineY = top + (int)size.Height + 3; while(lineY < bottom) { path.AddLine(left, lineY, right, lineY); // the following line is needed to prevent diagonal lines between the end // of the line just drawn and the start of the next line (if any) path.AddLine(right, lineY, left, lineY); lineY += (int)size.Height + 3; } int lineX = left; int topY = top + (int)size.Height + 3; path.AddLine(left, bottom - (int)size.Height + 3, left, topY); for(int col = 0; col < colWidths.Count - 1; col++) { if(col != colWidths.Count - 2 || box.ShowPseTnx) { lineX += (int)colWidths[col]; path.AddLine(lineX, topY, lineX, bottom); // the following line is needed to prevent diagonal lines between the end // of the line just drawn and the strt of the next line (if any); path.AddLine(lineX, bottom, lineX, topY); } } }
/// <summary> /// Create list of column widths /// </summary> /// <param name="g">Graphics object the card is being drawn on</param> /// <param name="font">Font in which text in the Qsos Box will be displayed</param> /// <param name="headers">List of column headers</param> /// <param name="box">Qsos box for which the column widths are being created</param> /// <returns>List of column widths</returns> protected List<float> CreateColumnWidths(Graphics g, Font font, List<string> headers, QsosWFBox box) { List<float> colWidths = new List<float>(); int width = 0; // date column width int dateLen = box.DateFormat.Length; string dateMeasure = string.Empty; for(int i = 0; i < dateLen; i++) { dateMeasure += "M"; } SizeF size =g.MeasureString(dateMeasure, font); colWidths.Add((int)size.Width); // time column width size = g.MeasureString("000000", font); width = (int)size.Width; size = g.MeasureString(headers[1], font); colWidths.Add(width >= (int)size.Width ? width : (int)size.Width); if(box.ShowFrequency) { colWidths.Add(0); // band column width // assuming frequency limited to 8 characters size = g.MeasureString("241000.0", font); width = (int)size.Width; size = g.MeasureString(headers[3], font); colWidths.Add(width >= (int)size.Width ? width : (int)size.Width); } else { // assuming 2190m is the largest band width size = g.MeasureString("2190m", font); width = (int)size.Width; size = g.MeasureString(headers[2], font); colWidths.Add(width >= (int)size.Width ? width : (int)size.Width); colWidths.Add(0); // frequency column width } // mode column width // assuming mode is limited to 12 characters (e.g. OLIVIA-BEACON) size = g.MeasureString("MMMMMMMMMMMM", font); colWidths.Add((int)size.Width); // rst column width // assuming signal report limited to 3 chars size = g.MeasureString("599", font); width = (int)size.Width; size = g.MeasureString(headers[4], font); colWidths.Add(width >= (int)size.Width ? width : (int)size.Width); // qsl column width if(box.ShowPseTnx) { // take largest width of header text, Pse text and Tnx text size = g.MeasureString(headers[5], font); width = (int)size.Width; size = g.MeasureString(box.PseText, font); width = width >= (int)size.Width ? width : (int)size.Width; size = g.MeasureString(box.TnxText, font); colWidths.Add(width >= (int)size.Width ? width : (int)size.Width); } else { colWidths.Add(0); } float totalColWidths = 0; for(int col = 0; col < colWidths.Count; col++) { totalColWidths += colWidths[col]; } BoxMinimumWidth = (int)(totalColWidths + 5); if(box.Width < BoxMinimumWidth) { box.ItemSize = new Size(BoxMinimumWidth, box.Height); } float colExpansion = (box.Width - totalColWidths) / (box.ShowPseTnx ? 6: 5); for(int col = 0; col < colWidths.Count; col++) { if(colWidths[col] != 0) { colWidths[col] += colExpansion; } } return colWidths; }
/// <summary> /// Create a list of Qsos box headers /// </summary> /// <param name="box">Qsos box for which we are creating the headers</param> /// <returns>List of column leaders</returns> protected List<string> CreateColumnHeaders(QsosWFBox box) { List<string> headers = new List<string>(); switch(box.DateFormat) { case "YYYY-MM-DD": headers.Add(box.YYYYMMDDText.Equals(string.Empty) ? "YYYY-MM-DD" : box.YYYYMMDDText); break; case "DD-MMM-YY": headers.Add(box.DDMMMYYText.Equals(string.Empty) ? "DD-MMM-YY" : box.DDMMMYYText); break; case "DD-MM-YY": headers.Add(box.DDMMYYText.Equals(string.Empty) ? "DD-MM-YY" : box.DDMMYYText); break; } headers.Add(box.TimeText.Equals(string.Empty) ? "Time" : box.TimeText); headers.Add(box.BandText.Equals(string.Empty) ? "Band" : box.BandText); headers.Add(box.FreqText.Equals(string.Empty) ? "MHz" : box.FreqText); headers.Add(box.ModeText.Equals(string.Empty) ? "Mode" : box.ModeText); headers.Add(box.RSTText.Equals(string.Empty) ? "RST" : box.RSTText); headers.Add(box.QSLText.Equals(string.Empty) ? "QSL" : box.QSLText); return headers; }
/// <summary> /// Paint the qsos box on the card. /// </summary> /// <param name="g">Graphics object on which to do the drawing</param> /// <param name="qsos">List of QSOs to paint on the card</param> /// <param name="qBox">QsosWFBox object to draw</param> /// <param name="fontAdjustmentFactor">amount to adjust font sizes by. This should be /// 1 except for images where it should be 96F/resolution</param> private void PaintQsosBox(Graphics g, List<DispQso> qsos, QsosWFBox qBox, float fontAdjustmentFactor) { Pen pen = new Pen(qBox.LineTextBrush, 1); g.SmoothingMode = SmoothingMode.AntiAlias; Font font = new Font(new System.Drawing.FontFamily( qBox.FontName), qBox.FontSize * fontAdjustmentFactor, FontStyle.Regular, GraphicsUnit.Point); List<string> colHeaders = CreateColumnHeaders(qBox); List<float> colWidths = CreateColumnWidths(g, font, colHeaders, qBox); GraphicsPath path = CreateOutsideBoxPath(qBox); FillQsosBoxBackground(g, path, qBox); CreateInsideBoxPath(g, ref path, font, colHeaders, colWidths, qBox); g.DrawPath(pen, path); DrawConfirmingText(g, font, qsos, qBox, fontAdjustmentFactor); DrawHeaders(g, font, colHeaders, colWidths, qBox); DrawQsos(g, qsos, font, colWidths, qBox); pen.Dispose(); if(QslCard.IsInDesignMode) { if(qBox.IsHighlighted) { g.DrawRectangle(highlighedPen, new Rectangle( CardLocation.X + qBox.X, CardLocation.Y + qBox.Y, qBox.Width, qBox.Height)); } else if(qBox.IsSelected) { g.DrawRectangle(selectedPen, new Rectangle( CardLocation.X + qBox.X, CardLocation.Y + qBox.Y, qBox.Width, qBox.Height)); } } }
/// <summary> /// Add a QsosWFBox to the card /// </summary> /// <returns>QsosWFBox that was added</returns> public QsosWFBox AddQsosBox() { QsosWFBox box = new QsosWFBox(true); box.QslCard = QslCard; box.IsSelected = true; QslCard.QsosBox = box; return box; }