private void SetupSoundControls() { if (m_innerView.WritingSystemsToDisplay == null) { return; // should get called again when it is set up. } if (m_innerView.RootBox == null) { return; // called again in MakeRoot, when information more complete. } int index = -1; foreach (var ws in m_innerView.WritingSystemsToDisplay) { index++; var pws = ws as WritingSystemDefinition; if (pws == null || !pws.IsVoice || MultiStringSelectionUtils.GetSelAtStartOfWs(m_innerView.RootBox, m_innerView.Flid, index, ws) == null) { continue; } var soundFieldControl = new ShortSoundFieldControl(); m_soundControls.Add(soundFieldControl); // todo: one for each audio one soundFieldControl.Visible = true; soundFieldControl.PlayOnly = false; var filename = m_innerView.Cache.DomainDataByFlid.get_MultiStringAlt(m_innerView.HvoObj, m_innerView.Flid, ws.Handle).Text ?? ""; string path; if (String.IsNullOrEmpty(filename)) { // Provide a filename for copying an existing file to. CreateNewSoundFilename(out path); } else { var mediaDir = FdoFileHelper.GetMediaDir(m_innerView.Cache.LangProject.LinkedFilesRootDir); Directory.CreateDirectory(mediaDir); // Palaso media library does not cope if it does not exist. path = Path.Combine(mediaDir, filename.Normalize(NormalizationForm.FormC)); // Windows in total defiance of the Unicode standard does not consider alternate normalizations // of file names equal. The name in our string will always be NFD. From 7.2.2 we are saving files // in NFC, but files from older versions could be NFD, so we need to check both. This is not // foolproof...don't know any way to look for all files that might exist with supposedly equivalent // names not normalized at all. if (!File.Exists(path)) { var tryPath = path.Normalize(NormalizationForm.FormD); if (File.Exists(tryPath)) { path = tryPath; } } } soundFieldControl.Path = path; soundFieldControl.BeforeStartingToRecord += soundFieldControl_BeforeStartingToRecord; soundFieldControl.SoundRecorded += soundFieldControl_SoundRecorded; soundFieldControl.SoundDeleted += soundFieldControl_SoundDeleted; Controls.Add(soundFieldControl); } }
/// <summary> /// Override to handle KeyUp/KeyDown within a multi-string field -- LT-13334 /// </summary> protected override void OnKeyDown(KeyEventArgs e) { base.OnKeyDown(e); if (!e.Handled && (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down)) { MultiStringSelectionUtils.HandleUpDownArrows(e, m_rootb, RootSiteEditingHelper.CurrentSelection, WritingSystemsToDisplay, m_flid); } }
/// <summary> /// User pressed a key. /// </summary> protected override void OnKeyDown(KeyEventArgs e) { if (!m_editingHelper.HandleOnKeyDown(e)) { base.OnKeyDown(e); } if (!e.Handled && (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down)) { MultiStringSelectionUtils.HandleUpDownArrows(e, RootBox, EditingHelper.CurrentSelection, WritingSystems, kflid); } }
/// <summary> /// Arrange our sound controls if any. /// </summary> protected override void OnLayout(LayoutEventArgs levent) { base.OnLayout(levent); if (m_innerView.VC == null || m_innerView.RootBox == null) // We can come in with no rootb from a dispose call. { return; } if (Visible) { m_innerView.RefreshDisplayIfPending(); // Reconstruct the innerView's RootBox only if it is pending. } int dpiX; using (var graphics = CreateGraphics()) { dpiX = (int)graphics.DpiX; } int indent = m_innerView.VC.m_mDxmpLabelWidth * dpiX / 72000 + 5; // 72000 millipoints/inch if (m_soundControls.Count == 0) { SetupSoundControls(); } foreach (var control in m_soundControls) { int wsIndex; var ws = WsForSoundField(control, out wsIndex); if (ws != null) { control.Left = indent; control.Width = Width - indent; control.Top = Height - indent + 5; var sel = MultiStringSelectionUtils.GetSelAtStartOfWs(m_innerView.RootBox, m_innerView.Flid, wsIndex, ws); if (sel != null) { // not sure how it could be null, but see LT-13984. Most likely we are doing it too // soon, perhaps before the root box is even constructed. // Leave control.Top zero and hope layout gets called again when we can make // the selection successfully. Rectangle selRect; if (m_innerView.GetSoundControlRectangle(sel, out selRect)) { control.Top = selRect.Top; } } // Don't crash trying to bring to front if control is not a child control on Linux (FWNX-1348). // If control.Parent is null, don't crash, and bring to front anyway on Windows (LT-15148). if (control.Parent == null || control.Parent.Controls.Contains(control)) { control.BringToFront(); } } } }