unit custom_menu; //{$DEFINE _DEBUG} //{$DEFINE ICON} interface uses Windows, Messages, SysUtils, Graphics, Controls, Forms, ComCtrls, ExtCtrls, StdCtrls, Grids, ActnList, Menus, Classes, ImgList, ToolWin, CheckLst, Buttons; // my_inifile; { type T_MenuAction = class(TObject) private F_sMenuCaption: WideString; F_MenuItem: TMenuItem; public constructor Create(AMenuItem: TMenuItem; sCaption: WideString); property Key: Word read F_iKey; property Action: TAction read F_Action; end; } type TForm_Custom_Menu = class(TForm) ActionList1: TActionList; actFile_Close: TAction; actMenu_Reset: TAction; actMenu_Test: TAction; actMenu_Popup: TAction; mnuMenu: TPopupMenu; mniMenu_Category: TMenuItem; mniMenu_Line1: TMenuItem; mniMenu_Test: TMenuItem; mniMenu_Reset: TMenuItem; mniMenu_Line2: TMenuItem; mniFile_Close: TMenuItem; Label_MenuText: TLabel; Panel_Cmd: TPanel; Button_Reset: TButton; Button_Close: TButton; GroupBox_Hint: TGroupBox; Label_Hint: TLabel; Panel_TreeView: TPanel; TreeView_Menu: TTreeView; Splitter1: TSplitter; Panel_CheckListBox: TPanel; CheckListBox_Menu: TCheckListBox; Button_Test: TButton; procedure FormCreate(Sender: TObject); procedure FormClose (Sender: TObject; var Action: TCloseAction); procedure actFile_CloseExecute(Sender: TObject); procedure actMenu_ResetExecute(Sender: TObject); procedure actMenu_TestExecute (Sender: TObject); procedure actMenu_PopupExecute(Sender: TObject); procedure CheckListBox_MenuClickCheck (Sender: TObject); procedure CheckListBox_MenuClick (Sender: TObject); procedure lstMenuKeyUp (Sender: TObject; var Key: Word; Shift: TShiftState); procedure lstMenuKeyPress (Sender: TObject; var Key: Char); procedure TreeView_MenuChange(Sender: TObject; Node: TTreeNode); procedure CheckListBox_MenuDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); procedure TreeView_MenuClick(Sender: TObject); private { Private 宣言 } procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND; procedure FSetHighDPIControlHeight; public { Public 宣言 } end; //------------------------------------------------------------------------------ procedure G_pcCreateMenuForm; //procedure G_pcReadIniMenu (AIniFile: TMyIniFile; AMenu: TMenu); //procedure G_pcWriteIniMenu(AIniFile: TMyIniFile; AMenu: TMenu); procedure G_pcCreateInitMenuVisible(AMenu: TMenu); procedure G_pcSetReadBinMenu; function G_fniWriteBinMenu(hHandle: THandle): DWORD; var Form_Custom_Menu : TForm_Custom_Menu; // G_MenuList: TList; //============================================================================== implementation uses {$IFDEF _DEBUG} myDebug, {$ENDIF} custom_base, custom_setting, custom_shortcut, my_settingfile, lang, highDPIUnit, common, main, general; {$R *.dfm} var F_MenuInitVisible : TStrings; //============================================================================== procedure G_pcCreateMenuForm; procedure _CreateForm; begin Form_Custom_Menu := TForm_Custom_Menu.Create(G_MainForm); end; var i: Integer; begin if (Form_Custom_Menu = nil) then begin _CreateForm; end else begin for i := 0 to Screen.FormCount -1 do begin if (Screen.Forms[i] = Form_Custom_Menu) then begin Exit; end; end; _CreateForm; end; end; procedure G_pcCreateInitMenuVisible(AMenu: TMenu); procedure _MenuVisibleSet(AMenuItem: TMenuItem); var i : Integer; l_MenuItem : TMenuItem; begin for i := 0 to AMenuItem.Count -1 do begin l_MenuItem := AMenuItem.Items[i]; if (Copy(AMenuItem.Items[i].Name, 0, 2) = '__') then begin //Nameの頭が'__'で始まるメニュー項目はリストから除外 Continue; end; //メニュー表示の初期値を格納 //VisibleがTrueなら'1'、Falseなら空文字。 if (l_MenuItem.Visible) then begin F_MenuInitVisible.AddObject('1', l_MenuItem); end else begin F_MenuInitVisible.AddObject('', l_MenuItem); end; if (l_MenuItem.Count > 0) then begin //サブメニューあり _MenuVisibleSet(l_MenuItem); end; end; end; begin _MenuVisibleSet(AMenu.Items); end; (* const lcsSECT_MENU = 'Menu'; procedure G_pcReadIniMenu(AIniFile: TMyIniFile; AMenu: TMenu); function lfn_FindMenuItem(sName: String; AMenuItem: TMenuItem): TMenuItem; var i: Integer; l_MenuItem: TMenuItem; begin Result := nil; sName := UpperCase(sName); if (sName = UpperCase(AMenuItem.Name)) then begin Result := AMenuItem; end else if (AMenuItem.Count > 0) then begin for i := 0 to AMenuItem.Count-1 do begin l_MenuItem := AMenuItem.Items[i]; if (sName = UpperCase(l_MenuItem.Name)) then begin Result := l_MenuItem; Exit; end else if (l_MenuItem.Count > 0) then begin Result := lfn_FindMenuItem(sName, l_MenuItem); if (Result <> nil) then begin Exit; end; end; end; end; end; var lsl_List: TStrings; i: Integer; l_MenuItem: TMenuItem; begin lsl_List := TStringList.Create; try if (AIniFile.SectionExists(lcsSECT_MENU)) then begin AIniFile.ReadSectionText(lcsSECT_MENU, lsl_List); //非表示にするメニューのNameプロパティのみが列挙されている for i := 0 to lsl_List.Count -1 do begin // l_MenuItem := lfn_FindMenuItem(lsl_List[i], AMenu.Items); l_MenuItem := G_MainForm.Get_IDMToMenuItem(gfniStrToInt(lsl_List[i])); if (l_MenuItem <> nil) then begin G_MainForm.SetMenuVisible(l_MenuItem, False); end; end; end; finally lsl_List.Free; end; end; procedure G_pcWriteIniMenu(AIniFile: TMyIniFile; AMenu: TMenu); procedure lpc_WriteMenu(AList: TStrings; AMenuItem: TMenuItem); var i: Integer; l_MenuItem: TMenuItem; begin for i := 0 to AMenuItem.Count-1 do begin l_MenuItem := AMenuItem.Items[i]; if (Copy(l_MenuItem.Name, 1, 2) = '__') then begin Continue; end; if not(l_MenuItem.Visible) then begin // AList.Add(G l_MenuItem.Name); AList.Add(IntToStr(G_MainForm.Get_MenuItemToIDM(l_MenuItem))); end; if (l_MenuItem.Count > 0) then begin lpc_WriteMenu(AList, l_MenuItem); end; end; end; var lsl_List: TStrings; begin //[Menu] lsl_List := TStringList.Create; try AIniFile.EraseSection(lcsSECT_MENU); lpc_WriteMenu(lsl_List, AMenu.Items); AIniFile.WriteSectionText(lcsSECT_MENU, lsl_List); finally lsl_List.Free; end; end; *) procedure G_pcSetReadBinMenu; procedure _SetMenuShow(AMenuItem: TMenuItem); var i : Integer; l_MenuItem : TMenuItem; begin for i := 0 to AMenuItem.Count-1 do begin l_MenuItem := AMenuItem.Items[i]; if (Copy(l_MenuItem.Name, 1, 2) = '__') then begin Continue; end; l_MenuItem.Visible := True; if (l_MenuItem.Count > 0) then begin _SetMenuShow(l_MenuItem); end; end; end; var i : Integer; l_MenuItem : TMenuItem; begin //表示しないメニューを列挙しているので、まずすべてのメニューを表示させる _SetMenuShow(G_MainForm.PopupMenu_Main.Items); for i := 0 to High(G_MenuHideItem) do begin l_MenuItem := G_MainForm.Get_IDMToMenuItem(G_MenuHideItem[i]); if (l_MenuItem <> nil) then begin l_MenuItem.Visible := False; end else begin {$IFDEF _DEBUG} //Beep; //myDebug.gpcDebug([i, 'NG']); {$ENDIF} end; end; end; function G_fniWriteBinMenu(hHandle: THandle): DWORD; procedure _GetHideMenu(AList: TList; AMenuItem: TMenuItem); var i: Integer; l_MenuItem: TMenuItem; begin for i := 0 to AMenuItem.Count-1 do begin l_MenuItem := AMenuItem.Items[i]; if (Copy(l_MenuItem.Name, 1, 2) = '__') then begin Continue; end; if not(l_MenuItem.Visible) then begin // AList.Add(IntToStr(G_MainForm.Get_MenuItemToIDM(l_MenuItem))); AList.Add(TObject(G_MainForm.Get_MenuItemToIDM(l_MenuItem))); end; if (l_MenuItem.Count > 0) then begin _GetHideMenu(AList, l_MenuItem); end; end; end; var l_List : TList; i : Integer; li_Count : Word; li_Write : DWORD; begin // Result := 0; l_List := nil; try l_List := TList.Create; _GetHideMenu(l_List, G_MainForm.PopupMenu_Main.Items); li_Count := l_List.Count; SetLength(G_MenuHideItem, li_Count); for i := 0 to High(G_MenuHideItem) do begin //myDebug.gpcDebug(lsl_List[i]); G_MenuHideItem[i] := Integer(l_List[i]); //myDebug.gpcDebug(G_MainForm.Get_IDMToMenuItem(G_MenuHideItem[i]).Name); end; WriteFile(hHandle, li_Count, SizeOf(li_Count), li_Write, nil); WriteFile(hHandle, G_MenuHideItem[0], SizeOf(Word) * li_Count, li_Write, nil); Result := SizeOf(li_Count) + SizeOf(Word) * li_Count; finally l_List.Free; end; end; //============================================================================== procedure TForm_Custom_Menu.WMSysCommand(var Msg: TWMSysCommand); begin case Msg.CmdType of 61587: begin //システムアイコンクリック actMenu_PopupExecute(nil); end; else begin inherited; end; end; end; procedure TForm_Custom_Menu.FSetHighDPIControlHeight; begin gpcLabelHeightSet(Label_MenuText); gpcItemHeightSet(CheckListBox_Menu); G_HintBoxHeightSet(GroupBox_Hint); TreeView_Menu.Height := Panel_TreeView.Height - (G_ciCONTROL_MARGIN * 2); G_ControlWidthSet(TreeView_Menu); CheckListBox_Menu.Height := TreeView_Menu.Height; // CheckListBox_Menu.Height := Panel_TreeView.Height - (G_ciCONTROL_MARGIN * 2); G_ControlWidthSet(CheckListBox_Menu); //ここで高さだけを調整すると幅が親ウィンドウ(AlignがalClinet)の幅に追随しない。 G_ControlTopSet(TreeView_Menu); G_ControlTopSet(CheckListBox_Menu); //下部のコマンドボタン部分の調整。 gpcButtonHeightSet(Button_Reset); gpcButtonHeightSet(Button_Test); gpcButtonHeightSet(Button_Close); G_PanelCmdHieghtSet(Panel_Cmd); G_ControlTopSet(Button_Reset); G_ControlTopSet(Button_Test); G_ControlTopSet(Button_Close); G_ControlLeftSet(Button_Reset, [Button_Test]); G_CloseButtonLeftSet(Button_Close); end; procedure TForm_Custom_Menu.FormCreate(Sender: TObject); procedure _MenuListSet(AMenuItem: TMenuItem); var i : Integer; l_MenuItem : TMenuItem; l_Action : TAction; l_Text : String; begin for i := 0 to AMenuItem.Count -1 do begin if (Copy(AMenuItem.Items[i].Name, 0, 2) = '__') or not(AMenuItem.Visible) then begin //Nameの頭が'__'で始まるメニュー項目はリストから除外 Continue; end; if (AMenuItem.Items[i].Count > 0) then begin l_MenuItem := AMenuItem.Items[i]; l_Action := TAction(l_MenuItem.Action); if (l_Action <> nil) then begin l_Text := l_Action.Caption; end else begin l_Text := l_MenuItem.Caption; end; TreeView_Menu.Items.AddChildObject(TreeView_Menu.Items[0], StripHotKey(l_Text), AMenuItem.Items[i]); //サブメニューあり //_MenuListSet(AMenuItem.Items[i]); end; end; end; var lh_Menu : HMENU; l_Menu : TMenu; begin {$IFDEF _DEBUG} // myDebug.gpcMessageModeSet(True); {$ENDIF} G_pcCreateCustomBaseForm; Self.ManualDock(G_CustomForm.tabMenu); Self.Align := alClient; Self.Icon := Application.Icon; Self.Visible := True; Panel_CheckListBox.Align := alClient; Label_Hint.Caption := ''; //システムメニュー lh_Menu := GetSystemMenu(Handle, False); DeleteMenu(lh_Menu, SC_RESTORE, MF_BYCOMMAND); //元のサイズに戻す DeleteMenu(lh_Menu, SC_MINIMIZE, MF_BYCOMMAND); //最小化 DeleteMenu(lh_Menu, SC_MAXIMIZE, MF_BYCOMMAND); //最大化 DrawMenuBar(lh_Menu); //高DPI対応 FSetHighDPIControlHeight; //メニュー l_Menu := G_MainForm.PopupMenu_Main; TreeView_Menu.Items.AddObject(nil, 'ルート', l_Menu.Items); _MenuListSet(l_Menu.Items); TreeView_Menu.Items.Item[0].Expand(True); TreeView_Menu.Select(TreeView_Menu.Items.Item[0]); end; procedure TForm_Custom_Menu.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := caFree; end; //閉じる procedure TForm_Custom_Menu.actFile_CloseExecute(Sender: TObject); begin G_CustomForm.actFile_CloseExecute(nil); end; procedure TForm_Custom_Menu.TreeView_MenuChange(Sender: TObject; Node: TTreeNode); var i : Integer; l_MenuItem : TMenuItem; l_Action : TAction; ls_Text : String; begin try CheckListBox_Menu.Items.BeginUpdate; CheckListBox_Menu.Items.Clear; Label_Hint.Caption := ''; l_MenuItem := TMenuItem(Node.Data); if (l_MenuItem <> nil) then begin for i := 0 to l_MenuItem.Count -1 do begin l_Action := TAction(l_MenuItem.Items[i].Action); if (l_Action <> nil) then begin ls_Text := l_Action.Caption; end else begin ls_Text := l_MenuItem.Items[i].Caption; end; CheckListBox_Menu.Items.AddObject(ls_Text, l_MenuItem.Items[i]); CheckListbox_Menu.Checked[i] := l_MenuItem.Items[i].Visible; end; end; finally CheckListBox_Menu.Items.EndUpdate; end; end; procedure TForm_Custom_Menu.TreeView_MenuClick(Sender: TObject); begin Label_Hint.Caption := ''; end; procedure TForm_Custom_Menu.CheckListBox_MenuDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); var l_MenuItem : TMenuItem; begin l_MenuItem := TMenuItem(CheckListBox_Menu.Items.Objects[Index]); if (l_MenuItem <> nil) then begin G_pcControlFontSet(CheckListBox_Menu.Canvas.Font, l_MenuItem); if (odSelected in State) then begin if (GetFocus = CheckListBox_Menu.Handle) then begin CheckListBox_Menu.Canvas.Brush.Color := clHighlight; CheckListBox_Menu.Canvas.Font.Color := clHighlightText; end else begin CheckListBox_Menu.Canvas.Brush.Color := clBtnFace; CheckListBox_Menu.Canvas.Font.Color := clBtnText; end; end else begin CheckListBox_Menu.Canvas.Brush.Color := CheckListBox_Menu.Color; CheckListBox_Menu.Canvas.Font.Color := CheckListBox_Menu.Font.Color; end; CheckListBox_Menu.Canvas.FillRect(Rect); Inc(Rect.Left, G_ciTEXT_MARGIN); if (l_MenuItem.Caption = '-') then begin //セパレータ CheckListBox_Menu.Canvas.MoveTo(Rect.Left, Rect.Top + gfniRectHeight(Rect) div 2); CheckListBox_Menu.Canvas.LineTo(Rect.Right, Rect.Top + gfniRectHeight(Rect) div 2); end else begin DrawText(CheckListBox_Menu.Canvas.Handle, PChar(StripHotKey(CheckListBox_Menu.Items[Index])), -1, Rect, DT_NOPREFIX or DT_SINGLELINE or DT_VCENTER); //煩わしい DrawText(CheckListBox_Menu.Canvas.Handle, PChar(CheckListBox_Menu.Items[Index]), -1, Rect, {DT_NOPREFIX or} DT_SINGLELINE or DT_VCENTER); end; end; end; //------------------------------------------------------------------------------ //メニュー procedure TForm_Custom_Menu.CheckListBox_MenuClick(Sender: TObject); var l_MenuItem : TMenuItem; l_Action : TAction; ls_Hint : String; begin //myDebug.gpcDebug('OnClick'); l_MenuItem := TMenuItem(CheckListBox_Menu.Items.Objects[CheckListBox_Menu.ItemIndex]); if (l_MenuItem = nil) then begin Exit; end; l_Action := TAction(l_MenuItem.Action); if (l_Action <> nil) then begin // ls_Hint := G_fnsCommandDescriptGet(l_Action); ls_Hint := G_fnsCommandHintGet(l_Action); end else begin ls_Hint := ''; end; Label_Hint.Caption := ls_Hint; end; //チェック procedure TForm_Custom_Menu.CheckListBox_MenuClickCheck(Sender: TObject); var l_MenuItem : TMenuItem; li_Index : Integer; begin //OnClickの前に起きる //myDebug.gpcDebug('OnClickCheck'); li_Index := CheckListBox_Menu.ItemIndex; if (li_Index < 0) then begin Exit; end; l_MenuItem := TMenuItem(CheckListBox_Menu.Items.Objects[li_Index]); l_MenuItem.Visible := CheckListBox_Menu.Checked[li_Index]; CheckListBox_Menu.Refresh; // G_MainForm.DrawNow; end; procedure TForm_Custom_Menu.lstMenuKeyPress(Sender: TObject; var Key: Char); begin if (Key = ' ') then begin Key := #0; end; end; procedure TForm_Custom_Menu.lstMenuKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); begin case Key of VK_F10: begin if not(ssAlt in Shift) and not(ssCtrl in Shift) then begin actMenu_PopupExecute(nil); Key := 0; end; end; end; end; //初期化 procedure TForm_Custom_Menu.actMenu_ResetExecute(Sender: TObject); var i: Integer; l_MenuItem : TMenuItem; l_Node : TTreeNode; begin if (gfniMessageBoxYesNo(G_csCusotmMenu_ResetMessage, G_csAPPTITLE) = ID_YES) then begin try Screen.Cursor := crHourGlass; Self.Enabled := False; l_Node := TreeView_Menu.Selected; if (l_Node = nil) then begin l_Node := TreeView_Menu.Items.Item[0]; end; for i := 0 to F_MenuInitVisible.Count -1 do begin l_MenuItem := TMenuItem(F_MenuInitVisible.Objects[i]); l_MenuItem.Visible := (F_MenuInitVisible[i] <> ''); end; TreeView_MenuChange(nil, l_Node); finally Self.Enabled := True; Screen.Cursor := crDefault; end; end; end; //テスト procedure TForm_Custom_Menu.actMenu_TestExecute(Sender: TObject); var lpt_Pos: TPoint; begin lpt_Pos := Self.ClientOrigin; G_MainForm.PopupMenu_Main.Popup(lpt_Pos.X, lpt_Pos.Y); end; procedure TForm_Custom_Menu.actMenu_PopupExecute(Sender: TObject); begin mnuMenu.Popup(Self.ClientOrigin.X, Self.ClientOrigin.Y); end; initialization F_MenuInitVisible := TStringList.Create; finalization F_MenuInitVisible.Free; end.