diff --git a/VfoOverlay.pas b/VfoOverlay.pas index 96946cc..f989903 100644 --- a/VfoOverlay.pas +++ b/VfoOverlay.pas @@ -58,6 +58,7 @@ type FCurDev: string; // имя текущего устройства ('' = default) FPanel: TFlyPanel; // открытая fly-out панель + FAudScroll: Integer; // прокрутка списка аудио-устройств (верхний индекс) FVolTrack: TRect; // трек громкости (локальные координаты) FVolDrag: Boolean; @@ -159,6 +160,8 @@ const HIT_VOL = -24; HIT_SPLIT = -25; HIT_TX = -26; + HIT_AUD_UP = -27; + HIT_AUD_DN = -28; HIT_AGC_PICK_BASE = 100000; HIT_DEV_BASE = 200000; @@ -173,6 +176,8 @@ const BAR_H = 24; ROW_H = 20; IGAP = 2; + AUD_ROW_H = 17; // высота строки устройства в AUD-панели + AUD_MAX_VIS = 6; // максимум видимых устройств (дальше — прокрутка) OVL_BASE_H = PAD + HDR_H + MET_H + FRQ_H + BAR_H + PAD; // = 96 // Палитра @@ -334,6 +339,7 @@ begin FVolume := 70; FMuted := False; FSplit := False; FTx := False; FTxSel := True; FSlice := 'A'; FPanel := fpNone; + FAudScroll := 0; FVolDrag := False; FDevNames := TStringList.Create; FCurDev := ''; @@ -387,7 +393,7 @@ begin case FPanel of fpMode: Result := ROW_H*2 + IGAP + ROW_H + IGAP; // 2 ряда режимов + ряд фильтров fpDsp: Result := ROW_H + IGAP + ROW_H; // toggles + AGC - fpAud: Result := Max(1, FDevNames.Count) * 17; + fpAud: Result := Min(Max(1, FDevNames.Count), AUD_MAX_VIS) * AUD_ROW_H; else Result := 0; end; end; @@ -401,6 +407,7 @@ end; procedure TVfoOverlay.SetPanel(P: TFlyPanel); begin if FPanel = P then FPanel := fpNone else FPanel := P; + if FPanel = fpAud then FAudScroll := 0; // список с начала Height := ComputeHeight; RequestInvalidate; end; @@ -681,11 +688,14 @@ begin end; procedure TVfoOverlay.DrawAudPanel(C: TCanvas; X, Y, RowW: Integer); +const + ARROW_W = 15; var - I: Integer; + I, Slot, VisN, RowWidth, MaxScroll, PanelH, ArrowX, MidY, CY: Integer; HR: TRect; Nm: string; - Cur: Boolean; + Cur, Scrollable, CanUp, CanDn: Boolean; + Tri: array[0..2] of TPoint; begin C.Font.Name := 'Courier New'; C.Font.Size := 7; @@ -697,9 +707,18 @@ begin C.TextOut(X, Y + 2, '(нет устройств)'); Exit; end; - for I := 0 to FDevNames.Count - 1 do + + VisN := Min(FDevNames.Count, AUD_MAX_VIS); + Scrollable := FDevNames.Count > AUD_MAX_VIS; + MaxScroll := FDevNames.Count - VisN; + if FAudScroll > MaxScroll then FAudScroll := MaxScroll; + if FAudScroll < 0 then FAudScroll := 0; + if Scrollable then RowWidth := RowW - ARROW_W - 2 else RowWidth := RowW; + + for Slot := 0 to VisN - 1 do begin - HR := Rect(X, Y + I*17, X + RowW, Y + I*17 + 16); + I := FAudScroll + Slot; + HR := Rect(X, Y + Slot*AUD_ROW_H, X + RowWidth, Y + Slot*AUD_ROW_H + 16); Nm := FDevNames[I]; Cur := (Nm = FCurDev) or ((FCurDev = '') and (I = 0)); if Cur then C.Brush.Color := CLR_ACCENT_D @@ -712,13 +731,50 @@ begin C.RoundRect(HR.Left, HR.Top, HR.Right, HR.Bottom, 4, 4); if Cur then C.Font.Color := CLR_ACCENT else C.Font.Color := CLR_TEXT; C.Brush.Style := bsClear; - if C.TextWidth(Nm) > RowW - 8 then - while (Length(Nm) > 1) and (C.TextWidth(Nm + '…') > RowW - 8) do + if C.TextWidth(Nm) > RowWidth - 8 then + while (Length(Nm) > 1) and (C.TextWidth(Nm + '…') > RowWidth - 8) do SetLength(Nm, Length(Nm) - 1); if Nm <> FDevNames[I] then Nm := Nm + '…'; C.TextOut(HR.Left + 4, HR.Top + (16 - C.TextHeight('A')) div 2, Nm); RegisterHit(HR, HIT_DEV_BASE + I); end; + + if not Scrollable then Exit; + + // Полоса прокрутки справа: ▲ (верх) / ▼ (низ) + счётчик позиции. + PanelH := VisN * AUD_ROW_H - 1; + ArrowX := X + RowWidth + 2; + MidY := Y + PanelH div 2; + CanUp := FAudScroll > 0; + CanDn := FAudScroll < MaxScroll; + + // верхняя стрелка + HR := Rect(ArrowX, Y, X + RowW, MidY - 1); + C.Brush.Color := CLR_BTN_NORM; C.Brush.Style := bsSolid; + C.Pen.Color := CLR_BTN_NORM; C.Pen.Style := psSolid; + C.RoundRect(HR.Left, HR.Top, HR.Right, HR.Bottom, 4, 4); + CY := (HR.Top + HR.Bottom) div 2; + if CanUp then C.Brush.Color := CLR_TEXT else C.Brush.Color := CLR_DIM; + C.Pen.Color := C.Brush.Color; + Tri[0] := Point((HR.Left+HR.Right) div 2, CY - 3); + Tri[1] := Point((HR.Left+HR.Right) div 2 - 4, CY + 2); + Tri[2] := Point((HR.Left+HR.Right) div 2 + 4, CY + 2); + C.Polygon(Tri); + RegisterHit(HR, HIT_AUD_UP); + + // нижняя стрелка + HR := Rect(ArrowX, MidY + 1, X + RowW, Y + PanelH); + C.Brush.Color := CLR_BTN_NORM; C.Brush.Style := bsSolid; + C.Pen.Color := CLR_BTN_NORM; C.Pen.Style := psSolid; + C.RoundRect(HR.Left, HR.Top, HR.Right, HR.Bottom, 4, 4); + CY := (HR.Top + HR.Bottom) div 2; + if CanDn then C.Brush.Color := CLR_TEXT else C.Brush.Color := CLR_DIM; + C.Pen.Color := C.Brush.Color; + Tri[0] := Point((HR.Left+HR.Right) div 2, CY + 3); + Tri[1] := Point((HR.Left+HR.Right) div 2 - 4, CY - 2); + Tri[2] := Point((HR.Left+HR.Right) div 2 + 4, CY - 2); + C.Polygon(Tri); + RegisterHit(HR, HIT_AUD_DN); end; { ---- Основная отрисовка ---- } @@ -893,6 +949,11 @@ begin if Assigned(FOnMute) then FOnMute(Self); Exit; end; HIT_SPLIT: begin if Assigned(FOnSplit) then FOnSplit(Self); Exit; end; HIT_TX: begin if Assigned(FOnTxSelect) then FOnTxSelect(Self); Exit; end; + HIT_AUD_UP: begin if FAudScroll > 0 then Dec(FAudScroll); + RequestInvalidate; Exit; end; + HIT_AUD_DN: begin if FAudScroll < FDevNames.Count - AUD_MAX_VIS then + Inc(FAudScroll); + RequestInvalidate; Exit; end; end; // Устройство аудио