diff --git a/internal/1.2.0/1/Design/PngComponentEditors.pas b/internal/1.2.0/1/Design/PngComponentEditors.pas new file mode 100644 index 0000000..a36113c --- /dev/null +++ b/internal/1.2.0/1/Design/PngComponentEditors.pas @@ -0,0 +1,223 @@ +unit PngComponentEditors; + +interface + +uses + Windows, SysUtils, Forms, Classes, Controls, PngImageList, TypInfo, + DesignIntf, DesignEditors, ColnEdit; + +type + TPngImageListEditor = class(TComponentEditor) + public + procedure Edit; override; + procedure ExecuteVerb(Index: Integer); override; + function GetVerb(Index: Integer): string; override; + function GetVerbCount: Integer; override; + end; + + TPngImageCollectionEditor = class(TComponentEditor) + public + procedure Edit; override; + procedure ExecuteVerb(Index: Integer); override; + function GetVerb(Index: Integer): string; override; + function GetVerbCount: Integer; override; + end; + + TPngButtonEditor = class(TComponentEditor) + public + procedure Edit; override; + procedure ExecuteVerb(Index: Integer); override; + function GetVerb(Index: Integer): string; override; + function GetVerbCount: Integer; override; + end; + + TPngImageListImagesEditor = class(TStringProperty) + public + procedure Edit; override; + function GetAttributes: TPropertyAttributes; override; + function GetValue: string; override; + end; + + TPngImageCollectionItemsEditor = class(TPngImageListImagesEditor) + public + procedure Edit; override; + end; + + TEditProperty = class + private + FPropery: string; + procedure EnumProperty(const Prop: IProperty); + public + constructor Create(Component: TComponent; const Prop: string; Designer: IDesigner); + end; + +implementation + +uses + PngImageListEditor; + +resourcestring + SEditImage = '&Edit image...'; + SRecreateImages = '&Recreate images...'; + SEditImages = '&Edit images...'; + SEditing = 'Editing %s.%s'; + SPNGObjectsHaveBeenCopied = 'The PNG objects have been copied to the internal imagelist.'; + +//This type is neccesary to be able to call CopyPngs without having to make it +//public in the TPngImageList class. +type + TPngImageListAccess = class(TPngImageList); + +procedure EditProperty(Component: TComponent; const Prop: string; Designer: IDesigner); +begin + TEditProperty.Create(Component, Prop, Designer).Free; +end; + +{ TPngImageListEditor } + +procedure TPngImageListEditor.Edit; +var + Component: TPngImageList; +begin + Component := GetComponent as TPngImageList; + EditProperty(Component, 'PngImages', Designer); // do not localize +end; + +procedure TPngImageListEditor.ExecuteVerb(Index: Integer); +begin + case Index of + 0: Edit; + 1: begin + TPngImageListAccess(GetComponent).CopyPngs; + MessageBox(0, PChar(SPNGObjectsHaveBeenCopied), + PChar(string(GetComponent.ClassName)), MB_ICONINFORMATION or MB_OK); + end; + end; +end; + +function TPngImageListEditor.GetVerb(Index: Integer): string; +begin + case Index of + 0: Result := SEditImages; + 1: Result := SRecreateImages; + end; +end; + +function TPngImageListEditor.GetVerbCount: Integer; +begin + Result := 2; +end; + +{ TPngImageCollectionEditor } + +procedure TPngImageCollectionEditor.Edit; +var + Component: TPngImageCollection; +begin + Component := GetComponent as TPngImageCollection; + EditProperty(Component, 'Items', Designer); // do not localize +end; + +procedure TPngImageCollectionEditor.ExecuteVerb(Index: Integer); +begin + Edit; +end; + +function TPngImageCollectionEditor.GetVerb(Index: Integer): string; +begin + Result := SEditImages; +end; + +function TPngImageCollectionEditor.GetVerbCount: Integer; +begin + Result := 1; +end; + +procedure TPngButtonEditor.Edit; +begin + EditProperty(GetComponent, 'OnClick', Designer); // do not localize +end; + +{ TPngButtonEditor } + +procedure TPngButtonEditor.ExecuteVerb(Index: Integer); +begin + EditProperty(GetComponent, 'PngImage', Designer); // do not localize +end; + +function TPngButtonEditor.GetVerb(Index: Integer): string; +begin + Result := SEditImage; +end; + +function TPngButtonEditor.GetVerbCount: Integer; +begin + Result := 1; +end; + +{ TEditProperty } + +constructor TEditProperty.Create(Component: TComponent; const Prop: string; Designer: IDesigner); +var + Components: IDesignerSelections; +begin + inherited Create; + FPropery := Prop; + Components := TDesignerSelections.Create; + Components.Add(Component); + GetComponentProperties(Components, tkAny, Designer, EnumProperty); +end; + +procedure TEditProperty.EnumProperty(const Prop: IProperty); +begin + if Prop.GetName = FPropery then + Prop.Edit; +end; + +{ TPngImageListImagesEditor } + +procedure TPngImageListImagesEditor.Edit; +var + ImageList: TPngImageList; + dlg: TPngImageListEditorDlg; +begin + dlg := TPngImageListEditorDlg.Create(nil); + ImageList := GetComponent(0) as TPngImageList; + dlg.Caption := Format(SEditing, [ImageList.Name, GetName]); + dlg.Images.Items.Assign(ImageList.PngImages); + dlg.ImageWidth := ImageList.Width; + dlg.ImageHeight := ImageList.Height; + if dlg.ShowModal = mrOK then begin + ImageList.PngImages.Assign(dlg.Images.Items); + Designer.Modified; + end; +end; + +function TPngImageListImagesEditor.GetAttributes: TPropertyAttributes; +begin + Result := inherited GetAttributes + [paDialog, paReadOnly]; +end; + +function TPngImageListImagesEditor.GetValue: string; +begin + Result := '(PNG images)'; // do not localize +end; + +{ TPngImageCollectionItemsEditor } + +procedure TPngImageCollectionItemsEditor.Edit; +var + Collection: TPngImageCollection; + dlg: TPngImageListEditorDlg; +begin + Collection := GetComponent(0) as TPngImageCollection; + dlg := TPngImageListEditorDlg.Create(nil); + dlg.Caption := Format(SEditing, [Collection.Name, GetName]); + dlg.Images.Items.Assign(Collection.Items); + if dlg.ShowModal = mrOK then begin + Collection.Items.Assign(dlg.Images.Items); + Designer.Modified; + end; +end; + +end. diff --git a/internal/1.2.0/1/Design/PngComponents.dcr b/internal/1.2.0/1/Design/PngComponents.dcr new file mode 100644 index 0000000..83ad90b Binary files /dev/null and b/internal/1.2.0/1/Design/PngComponents.dcr differ diff --git a/internal/1.2.0/1/Design/PngComponentsRegister.pas b/internal/1.2.0/1/Design/PngComponentsRegister.pas new file mode 100644 index 0000000..e538dd9 --- /dev/null +++ b/internal/1.2.0/1/Design/PngComponentsRegister.pas @@ -0,0 +1,41 @@ +unit PngComponentsRegister; + +interface + +uses + Classes, DesignIntf, TypInfo, + PngSpeedButton, PngBitBtn, PngImageList, PngCheckListBox, PngComponentEditors; + +procedure Register; + +implementation + +const + SPageName = 'Png'; + +procedure Register; +begin + //Register all components + RegisterComponents(SPageName, [TPngSpeedButton, TPngBitBtn, TPngImageList, + TPngImageCollection, TPngCheckListBox]); + + //Register component editors + RegisterComponentEditor(TPngImageList, TPngImageListEditor); + RegisterComponentEditor(TPngImageCollection, TPngImageCollectionEditor); + RegisterComponentEditor(TPngBitBtn, TPngButtonEditor); + RegisterComponentEditor(TPngSpeedButton, TPngButtonEditor); + + //Register property editors + RegisterPropertyEditor(TypeInfo(TPngImageCollectionItems), TPngImageList, + 'PngImages', TPngImageListImagesEditor); // do not localize + RegisterPropertyEditor(TypeInfo(TPngImageCollectionItems), TPngImageCollection, + 'Items', TPngImageCollectionItemsEditor); // do not localize + + //Hide properties that should be omitted + UnlistPublishedProperty(TPngSpeedButton, 'NumGlyphs'); // do not localize + UnlistPublishedProperty(TPngSpeedButton, 'Glyph'); // do not localize + UnlistPublishedProperty(TPngBitBtn, 'NumGlyphs'); // do not localize + UnlistPublishedProperty(TPngBitBtn, 'Glyph'); // do not localize +end; + +end. diff --git a/internal/1.2.0/1/Design/PngImageListEditor.dfm b/internal/1.2.0/1/Design/PngImageListEditor.dfm new file mode 100644 index 0000000..3a8c8f5 --- /dev/null +++ b/internal/1.2.0/1/Design/PngImageListEditor.dfm @@ -0,0 +1,574 @@ +object PngImageListEditorDlg: TPngImageListEditorDlg + Left = 202 + Top = 128 + BorderIcons = [biSystemMenu] + Caption = 'Editing PngImageList' + ClientHeight = 288 + ClientWidth = 461 + Color = clBtnFace + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = False + Position = poScreenCenter + OnClose = FormClose + OnCreate = FormCreate + OnResize = FormResize + OnShow = FormShow + PixelsPerInch = 96 + TextHeight = 13 + object pnlMain: TPanel + Left = 0 + Top = 0 + Width = 461 + Height = 249 + BevelOuter = bvNone + TabOrder = 0 + DesignSize = ( + 461 + 249) + object gbxProperties: TGroupBox + Left = 8 + Top = 4 + Width = 177 + Height = 128 + Anchors = [akLeft, akTop, akBottom] + Caption = 'Image properties' + TabOrder = 0 + object lblName: TLabel + Left = 10 + Top = 20 + Width = 31 + Height = 13 + Caption = '&Name:' + FocusControl = edtName + end + object lblBackgroundColor: TLabel + Left = 10 + Top = 64 + Width = 86 + Height = 13 + Caption = '&Background color:' + FocusControl = cmbBackgroundColor + end + object edtName: TEdit + Left = 8 + Top = 35 + Width = 161 + Height = 21 + TabOrder = 0 + OnChange = edtNameChange + end + object cmbBackgroundColor: TComboBox + Left = 29 + Top = 79 + Width = 140 + Height = 21 + ItemHeight = 0 + TabOrder = 2 + OnChange = cmbBackgroundColorChange + OnDblClick = cmbBackgroundColorDblClick + OnExit = cmbBackgroundColorExit + end + object pnlBackgroundColor: TPanel + Left = 8 + Top = 79 + Width = 20 + Height = 21 + BevelOuter = bvNone + BorderStyle = bsSingle + TabOrder = 1 + OnClick = cmbBackgroundColorDblClick + end + end + object lbxImages: TListBox + Left = 276 + Top = 8 + Width = 177 + Height = 209 + Style = lbOwnerDrawVariable + Anchors = [akLeft, akTop, akRight, akBottom] + DragCursor = crDefault + DragMode = dmAutomatic + ItemHeight = 16 + MultiSelect = True + TabOrder = 3 + OnClick = lbxImagesClick + OnDblClick = lbxImagesDblClick + OnDragOver = lbxImagesDragOver + OnDrawItem = lbxImagesDrawItem + OnEnter = lbxImagesEnter + OnExit = lbxImagesExit + OnKeyDown = lbxImagesKeyDown + OnMeasureItem = lbxImagesMeasureItem + OnMouseUp = lbxImagesMouseUp + OnStartDrag = lbxImagesStartDrag + end + object cmbPreviewBackground: TComboBox + Left = 276 + Top = 220 + Width = 177 + Height = 21 + Style = csOwnerDrawFixed + Anchors = [akLeft, akRight, akBottom] + ItemHeight = 15 + TabOrder = 4 + OnChange = cmbPreviewBackgroundChange + OnDrawItem = cmbPreviewBackgroundDrawItem + Items.Strings = ( + 'Default background' + 'Checkerboard background' + 'Diamonds background' + 'Slashed background' + 'Backslashed background') + end + object gbxImageInfo: TGroupBox + Left = 8 + Top = 136 + Width = 177 + Height = 105 + Anchors = [akLeft, akBottom] + Caption = 'Image information' + TabOrder = 1 + object lblDimensions: TLabel + Left = 8 + Top = 20 + Width = 70 + Height = 13 + Alignment = taRightJustify + AutoSize = False + Caption = 'Dimensions:' + end + object lblColorDepth: TLabel + Left = 8 + Top = 36 + Width = 70 + Height = 13 + Alignment = taRightJustify + AutoSize = False + Caption = 'Color depth:' + end + object lblTransparency: TLabel + Left = 8 + Top = 52 + Width = 70 + Height = 13 + Alignment = taRightJustify + AutoSize = False + Caption = 'Transparency:' + end + object lblCompression: TLabel + Left = 8 + Top = 68 + Width = 70 + Height = 13 + Alignment = taRightJustify + AutoSize = False + Caption = 'Compression:' + end + object lblFiltering: TLabel + Left = 8 + Top = 84 + Width = 70 + Height = 13 + Alignment = taRightJustify + AutoSize = False + Caption = 'Filtering:' + end + object lblDimensionsValue: TLabel + Left = 82 + Top = 20 + Width = 87 + Height = 13 + AutoSize = False + ShowAccelChar = False + end + object lblColorDepthValue: TLabel + Left = 82 + Top = 36 + Width = 87 + Height = 13 + AutoSize = False + ShowAccelChar = False + end + object lblTransparencyValue: TLabel + Left = 82 + Top = 52 + Width = 87 + Height = 13 + AutoSize = False + ShowAccelChar = False + end + object lblCompressionValue: TLabel + Left = 82 + Top = 68 + Width = 87 + Height = 13 + AutoSize = False + ShowAccelChar = False + end + object lblFilteringValue: TLabel + Left = 82 + Top = 84 + Width = 87 + Height = 13 + AutoSize = False + ShowAccelChar = False + end + end + object pnlActionButtons: TPanel + Left = 193 + Top = 35 + Width = 75 + Height = 178 + Anchors = [akLeft] + BevelOuter = bvNone + TabOrder = 2 + object btnAdd: TPngBitBtn + Left = 0 + Top = 0 + Width = 75 + Height = 25 + Caption = '&Add' + TabOrder = 0 + OnClick = btnAddClick + Layout = blGlyphRight + Margin = 6 + Spacing = 3 + PngImage.Data = { + 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF + 610000001974455874536F6674776172650041646F626520496D616765526561 + 647971C9653C000002804944415478DA8D925D48145114C7FF33AEBB7725BF52 + 23B31E8D908C08EB210885A8C0879630B132320A3114C2972232049F22E893BE + E82125A32CF13362C3079505832CB34811524837025B4557F7EBEEECDC3BB7AB + A3D52846070E773867FEBF39FF734711426021B2CFF454C6547BADA638D29599 + A92FB648A88E33FE8A85A382852958240A1692A77CD6231A04BFBEA85396015B + 4E7BC239FB7625541424A2FECD24FA5EBF178E90FFAAE046CD7F01369579A8EB + 643E797800189E05EADC4174B5F4439D186B8CE3BC5AA79AFFDF8013DD34FFD8 + 7E72710F1033005D01DA87389E37F421F8F1934765AC5C4E31B62660637117CD + 2B3944CA738108930D0970DA81FE1F024F1B07E0EBEA1DB569E152A6F1015DDA + 5905D8E072D36D2585E4683610D56136653A1DC04408686B1BC14453874F9DF3 + 5719DC6835F80D2B20A3B0936E2E7691822C6981C3128E7820205FEBE9F662BC + FE8586E9C90B42DCBE6B01A41D6CA5C9454564472AC00C53C88539459C0AD864 + EA36E0C3A00F53B71E4445A8CE6901AC2F7849D523252493008659324FC504E9 + 6C6114C03FEEC3FC3D0908AE00A4EC7D4623AE5222F558D263A1A51B660AB950 + 7CFD06743469989D9216EE582D24ED7E428387CB088C65F552CAD115B90331F8 + 197037FB40035580BD55889BD62526ED7C4C95E36709D89FE529EAA211447A7A + A1F7BA47C163A540FC8039DD0A404AEE239A71AE8208DDF4ADCAAF72CA30DDD2 + 8EE0BBB71E592C973986DFF656005273EED3ED97AB088BCA8D4BBF81F19FF036 + 77627E64A85156AA25D2FFF7D5AE02ACCBBA16CE3B7F2A216D6B26BC9E610C37 + 3447B5C08CFC5BEC57CCCBB4C62A80CD79A9D2999C589B909E9A3EE7FD3E140B + 856BA45F37D68865C02F696882F0CDD367480000000049454E44AE426082} + PngOptions = [pngBlendOnDisabled, pngGrayscaleOnDisabled] + end + object btnDelete: TPngBitBtn + Left = 0 + Top = 29 + Width = 75 + Height = 25 + Caption = '&Delete' + TabOrder = 1 + OnClick = btnDeleteClick + Layout = blGlyphRight + Margin = 6 + Spacing = 3 + PngImage.Data = { + 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF + 610000001974455874536F6674776172650041646F626520496D616765526561 + 647971C9653C0000026B4944415478DA8D935948545118C7FF779B7BE7CEA233 + A913068D46E38339916225B43866B48C94630E961562D1438821E44B3D0D483E + 842F06D9824259894942168542055AD04B0D0519D1F2580E895B33317366BBB7 + 338E4533B9F487EF5CEE39DFF73BDFF91F0EA3AA2A1262D85608B2085EA75D08 + 09BCAC05A793184EE00EC664BD0759391BC578784AA346DA3EDFA8BC325FB712 + 003CDB1ED69BCEEF38B08539B93F17D7470378FFDC1BFCDAEBD02D0F904593C2 + 729D6ABEAD618FBB0C9E2A03369881A627C0D0AD51E2BBEDD02E0D90259BC2F3 + DD86D292F2A38DDBE1B27310689AC0021DAF80B1FEA7C4D7BF7B3180044EE44A + E3A2AECFB2B7A2E058C3666C5DC32018051269320FF4BC03BC0323E4FBE0BE54 + 004B012CC7D42A99E62E6BBDCB525D5308AB1E08856931929204E0FE17E0D3C0 + 6332F9B02AAD03A6E50CB2733BF21A0F8B3B2BF360A473E11852A4E1801713C0 + B77B43646AD89506D07B42592D4D5271B1057C04882D6CCBFC19929F37D34064 + 6890CC3E73A7010C9E5046739394B3DE827868219B2EC569286AF2D74FC173B4 + 2BD3F05D32337664912398733AF843F5225BB88EF64FEBE3C94E54E5AF735023 + 331EDD21732F8FA703CED231520BADB10BCE3A0B4A3601D47D28A93E80FA6078 + 7093F8BD8D8B01128A9682D3F40915CE02795745E27EFEE940E9EF2181B7A796 + 0224A4DA68741BCAB69567BB6BC0697928D1A4270CBDCAC9ABD7C88FF1D3CB01 + 12524CD481CE8C427B83B5AE1AC6FCD58851137909186FBF4C663F34AF044072 + 4B442E88C655AD4527EA24ABA308D31F7D787DA937F873E29CEE3F00BF15756A + F4BAF64CEB5A7B7072662AE40FB4C5C8C5F9E7FC0BBF2FFCE106AF47A6000000 + 0049454E44AE426082} + PngOptions = [pngBlendOnDisabled, pngGrayscaleOnDisabled] + end + object btnReplace: TPngBitBtn + Left = 0 + Top = 58 + Width = 75 + Height = 25 + Caption = '&Replace' + TabOrder = 2 + OnClick = btnReplaceClick + Layout = blGlyphRight + Margin = 6 + Spacing = 3 + PngImage.Data = { + 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF + 610000001974455874536F6674776172650041646F626520496D616765526561 + 647971C9653C000003464944415478DA5D525B4C5457145DE70EC3D0995B2582 + 8A112316FBD12698C6F8200A3206A90A43438C3AB5C6D6261325FAD3F4A3F607 + DBFEF92121468D1AA2898FD8001518CC84A94AC6AA959AB64322FED854014306 + 9D1106B833F7FD70DF3B62D49DEC7372CED96BEDB5F73EAC7CFFC05185E5B768 + 8A9A2E10670EE8B2D6AB4B0AC8161A8CEBD05CDE6A6B3A3DEC1233BB74597DA2 + 8B0A0C4986264AB074136C6968305BD3B0D6CB341591CEC1143FF33CA82946CC + 54D490AF6255FB3707D7221A7E8CA15FA3718FAE345282C43B04A5CDFF668E7D + BFDAB7BD0CD877258B3B5DB713FC6CD22F8B6ADDA70D9B4E477FF9040F93C0FE + 9FE378168EC65C9619342425F5866049E8817028B48E0F7E0C8C668196EE690C + 77FF1ECF9F4A8EAFDCEEFFA2F5BB0A147B80072F8023C7E34847FA7B3851DCAB + C98AE410947C3B28ECF9BA92DFB20CD04C2029036DE1098C748451B6B9123F1D + FE0C8487270F187C0E9C68BB874C24729EA96AB3695A3A5BB4EFAEB06D4F15BF + 613120E980DB0508B45FBE3E0AFEC302046B4BE0B2008BBC8048FE22259DADFD + 9007A2672C703FB0E2AFFE10D6EDD8C4571402AA418194CDCD0122030C3A7B69 + 37E992D973A1C5E306224F4D0C9FEE02E27FB6B1A2604C280FF8F98FBCB912E6 + 8C63B9DD06CF997DA5D3F93E3535F992649E3B9161453B6F09F3EA6AF945C44C + 3D7100D66B02DB5FF33825D80AC7668119C242A5E52C112C68BA2168D5757CBE + 95BB538C1C497E01B94DA0E752DBEA32F6FF7239BA806B9DC0D0FD565618880A + D3EBB7F2D0904BCD7241ECFFFF607D40752D2975E2E76A60D448ABBF8F4672E3 + 2475EB47B6A03E22E835F50E01B3C114608C8C41EBBA88BCAA5AB8366C84F3C6 + E5C0E2CD01A837C3E7A9C066721A63FD75615E4380B7543A521FE4F11798ECB8 + FAB7369118290C34ED9E5FB3D1A99F235553B7EE61B2B7A787BEE05E922939A2 + 4A037D99E5C1461FA8F6EC441AA397AE26C4C4845F97D4CFCB76EF3855B2A5D2 + 513616BE8DF1EEDF62243B48B0D49BC994545DCAAE39F8A557991131D4DE999A + 1D7B16E45C793179321D5AB1CDDFBEE670131EF7FD8347172EC74D038D943981 + B78CCD2F6F3DEAE67D2DA6A4A4332FA70E701CD7ABCE6661AADAC23C8FBBC357 + 5C549D4D4D0EEBAABC8BC04FF09EBD02E1D692A4E09B28E50000000049454E44 + AE426082} + PngOptions = [pngBlendOnDisabled, pngGrayscaleOnDisabled] + end + object btnClear: TPngBitBtn + Left = 0 + Top = 87 + Width = 75 + Height = 25 + Caption = '&Clear' + TabOrder = 3 + OnClick = btnClearClick + Layout = blGlyphRight + Margin = 6 + Spacing = 3 + PngImage.Data = { + 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF + 610000001974455874536F6674776172650041646F626520496D616765526561 + 647971C9653C000003094944415478DA6D935B48145118C7FFB373E6BA9BDBBA + ADB58BE1A5A8970CB4A28C8A966EA696DA45ED22452515296A12BD45E14B4545 + 0F15223D1414B545216D8558A2A6899544D8432F964611994617775777DD9DE9 + 9B59A5A80E733867BE6FFEBFF3FDBFE170400D38DE02A6CA608A0C5E95C06471 + 96A6DA6E730E47068B8E76303D560270434C11C1CB426158B137088AE410F570 + 1DF70F40163C1126F933B7ADCFCA299A8B2BF5CF11ECED2DE725F1B220F1DE80 + 7D862FBF24DBA50912DAEFBF08FD05905C518EF7A514AEF35E39BE00F3938075 + C7DEE0CD83F643B2223E0AD893DA56147B3DD7765AF17000387AF665F0374016 + 155D55AF3BF2728B4E1DC9C2E2E9C07018A83DFF1A7D0FDBEE45125DC9199B73 + B2EA364D45AA15F0F501971A9E05E2008E6310C57A6B7EEEDEEAC3CB914DE270 + 94268013175EA1BFB51BE9A505A82970234906040BF0F80370E36AB701A8B601 + B1D3CAAA9C83C5B5B95842E23112739489D1F4B57C4660640C651B52318501E3 + 3140A1B56B1068BAD169002ACF2173694D464531F2D22D088FD3B1BAF9C042D9 + 106D781E50691DD7084C7191DE5F7F079EDF794200F79911ECAFB2254D63584A + 4D635C5C3C390C8831B43F8286857721E0ADBF750270A0CA0691C14EA5A524C4 + 4FE02684FA84D898DC049011E00B55FAB3B9C5B470862CD46273B19126E3804D + 8A9F625A216884B691D1B85822B868C40CD09366B3892AB93B89ECB595DCFA8D + D0A3F8EDC1807CFA086E2C047DF61C136EE68C5204606A7753FC375281C4D4EA + C535057BD535AB4C886E348C3E8A763D45B4E33184ADBBC1A7A75080727A1CC0 + DA1F4C028C1153C0B1EBCEC2A2A2C4D5CBA0C5E27DF8D1DE896FFEC65BA2DB93 + E62CDDB1484E9E0E8DFC7322E5EEFBFF04982D73911D5FF2A62DDE948295D0A8 + 8AC1962E0CF8EE56D03D69563DEEB6D45DDB3D56B783FE2DF0FEA63FF817C0AC + C463E1E19FB7A72C6BEEC685E8B9D888FEA6D67239D171598BC5BC0969337D99 + FB4A5C925D454FFDCDD07F0026641613E5DB5697332338FCB5231A1E2FB1086C + 484CB05155D142DB34678385AE732410ACFB05147F0B83A25F23860000000049 + 454E44AE426082} + PngOptions = [pngBlendOnDisabled, pngGrayscaleOnDisabled] + end + object btnUp: TPngBitBtn + Left = 0 + Top = 124 + Width = 75 + Height = 25 + Caption = '&Up' + TabOrder = 4 + OnClick = btnUpClick + Layout = blGlyphRight + Margin = 6 + Spacing = 3 + PngImage.Data = { + 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF + 610000001974455874536F6674776172650041646F626520496D616765526561 + 647971C9653C0000021C4944415478DAA5933B68535118C7FFE7DE247D886821 + 26197C504C8A5894D2461087BA38A874503B89521F9B858E0AA28BA08B1D1C14 + 412D48EB031D62972E6D8DD84987802D8A1645712AA6A995368F7BCFDB737223 + B44171C8E17CE783EF5E7EE7FBFEF77F89D61A8D2CD23020753E0B68BBAB07A0 + ECA121851CF211B9A928835B2A5E9294DE16C50A44C983CDAC5481E6F2EF0025 + 44BF1F6A79D27B38DD04A530FD7C863A3F0BA714E599FF038448AF8AD0C48143 + DDF13B27DB400870617411D9B1A97CB357EC931ECBF17F0374CAA37A626BF79E + 8ECB2712D81209E65C12C0B587DF309F99FC1C617E1FAFD02FAC585E03B04BA9 + 362ED4787847EAE0E923ED486E02CA3C78B4C180BE9680FB0F7258CEBE9E218C + 1F371DFC5AD781E4629447B70DECEFDD85DD51029F013CD01361076869023E2D + 294C8E4CC37BFB664C7371467155034871BDD81ABB92E8DA8B8EA8032103396C + 4805840C4098CC4C616E41A0F0E8199C8FB337941BBE4A5267A78E5244322BED + FB9AE3B156386B6CA1AB46017C334AA16C46A2A61036B5FC22F0F49EAF970BFD + 64E7B957EF56E29D5D7C730C9A0437592BB824080BA4352D1C52231B887AFF01 + FE8BC7B324399813A1CE1E574BABA301A00E60BB2075F63345C708FB7DF8AE24 + C981973F123DE9F8C698915DD9B7AB1BEB0C5E07704266A4F905CCDD1AC993ED + C7C6075DD71DB697492ACDB765904C40D9E036F35AFCA905F3B0B2A7E86AE962 + E33F53A380DF494945E019F9A78D0000000049454E44AE426082} + PngOptions = [pngBlendOnDisabled, pngGrayscaleOnDisabled] + end + object btnDown: TPngBitBtn + Left = 0 + Top = 153 + Width = 75 + Height = 25 + Caption = '&Down' + TabOrder = 5 + OnClick = btnDownClick + Layout = blGlyphRight + Margin = 6 + Spacing = 3 + PngImage.Data = { + 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF + 610000001974455874536F6674776172650041646F626520496D616765526561 + 647971C9653C000002174944415478DAB5934F68134114C6BFCD6E936AFF482B + 521A3555AC52D4D21EF620586C4104FF1D2C257810ADA5148AC5A35E144F7A50 + 111141105A44AD07853482C593158A2749A1912A88550F82D5DA966CB2D96E76 + 6667C7994D0824F1161C18DEEEDB79BFF7E6FB5885738E6A965235A07D68E682 + E3A9B719E3014E5D7894C22322120A26222F4617CCFF4EFCC8D2A607C3B8A444 + 86DFFD8EE85D2DBBDA1AE079E5F8B257259FD3346021F1137337279695D69184 + 3B7A5E574FB50386535153B254592CF6C620F0F207702DFA8029E1E8EBF9B0DE + DD1DED6B459D0A30AFB25042B500F0C70252A249631D30F5E2233E3D9C4C2A6D + FD53C7B3448D6D3BDC5B7B68FF26410078D9D812FA6105F8BC0AE404A866750D + C6DD7B39ACA70694ADC79E83DBCE75AB297C65FB913EEC6856C10A105EE8BE68 + 00DF5205A2EB02938F80AFC91B40E8AA123E2A000E0535ADC774E7DE73F53D07 + 119417155DA5C32601D67252004914C9780C48CC3E11730C4A7C1E202CA2996C + 13B349DCEE3CD0EB76E9E06EFEBCEF8C1C430887B733C09B57B3E2A91F08F833 + 1501C4B4C032D66E97B269D673628FB6AF03ACE04A6003E0BC4F82C49F7E1182 + 9C14D9C5A2462500D3064D9B3AD782D35BA2A75BEA3B223E21B3F01D4B13E3CB + CC324571CD5C89431580EC3A889119A86DDEFCAC73EC6C480A317F67DCB1577E + 9D11F7885558FC2F80BF4DEB62A8B1E1163C8E5CDAB82C54BCFF7F7EA66A017F + 01C92B1C3633E7F2D20000000049454E44AE426082} + PngOptions = [pngBlendOnDisabled, pngGrayscaleOnDisabled] + end + end + end + object pnlButtons: TPanel + Left = 0 + Top = 249 + Width = 461 + Height = 37 + BevelOuter = bvNone + TabOrder = 1 + DesignSize = ( + 461 + 37) + object pnlModalButtons: TPanel + Left = 152 + Top = 4 + Width = 158 + Height = 25 + Anchors = [akBottom] + BevelOuter = bvNone + TabOrder = 0 + object btnOK: TPngBitBtn + Left = 0 + Top = 0 + Width = 75 + Height = 25 + Caption = '&OK' + Default = True + ModalResult = 1 + TabOrder = 0 + PngImage.Data = { + 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF + 610000001974455874536F6674776172650041646F626520496D616765526561 + 647971C9653C000001D44944415478DAC5934148146118869F7F669ADD550221 + 5C5110090FDB25820E2B052D754848F010648487D214098930A443E521F02228 + E52D4AA873744828DA20483A48D6C15B5D4294D2924A6D0F5B63EB36BEF3AF44 + 222D8287061E66BEE17B9F9DEF9B1D1386213B39CC8E05DCA49E353E9257F543 + FC146BC213BED8F5D7B5B751FB34FA31BA5C97FD8661A629709D55B26505D1D9 + A58E18E771E85115188F36E30C39AF5DDF6D2C7C2BB44934B145109D43F65049 + 77554355673C164F2DCE2C4E4A72C654326FCC35D39FCC24477273B9F9E06D70 + 5AEDAF242A050D35929CF4EABD3EF5A4BC658F85C9856CB150ECA6824FA6226A + E925E337FBCF9D238E1FDC096699E394A2EF44070D7498C3A629914E60A60CF9 + A7F9871AA38738DF05254117493566B9CC41BE28768F198DB14486348754578B + 47E209A3FAD51BEC266747FB23E85451E43617B9404AD71F84236A4534CA036D + E40DB7B4BCABDA435112360BDAA37D6AB327B8CB513D60B8D1B0221E8B69AE28 + 38226C68ABA0D53EC13EF6F292731A277A5DCB625CDAF75C5270CC8612FF12B4 + 584174E3859EE318BFECBC2B1AA55FCDF76D205E4E705CC56FFB4719E000837C + E6ABC267F51A9F6D0A9615948EB41893AC4F4B9CB07762DB10FCF7AF711D7610 + 84C5CCB842D50000000049454E44AE426082} + end + object btnCancel: TPngBitBtn + Left = 83 + Top = 0 + Width = 75 + Height = 25 + Cancel = True + Caption = '&Cancel' + ModalResult = 2 + TabOrder = 1 + PngImage.Data = { + 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF + 610000001974455874536F6674776172650041646F626520496D616765526561 + 647971C9653C000002E24944415478DA6D93CB4F135114C6BF79B5451E022D42 + B0C5C82321206A58812B4AD8B8D2981077B22BB4087F4C1BCA232E64E38618FF + 00096C30411E0B44A031214140A10FFAA02D7DCCDCB99E3B8A4074929399CC9D + EF37F77EDF39D2D1230012C00DDCA1EA3638964B65A05C02741D600C372EC380 + 9773EC98266206AD49478F495C42BDEA541750533198DFCB064837FD3F0089FD + 352E255CCA9A4BD92C1FE640523A7C8066B5D6365FF7EAC590E66EC149F88D99 + DE4C4E3219537AF90A40B07197C7166CEFF7C8D9E30CBE7D4E2CE62E30221D76 + 6240BB5FB5DCF03A00D9D104F3C7571CBF7D6F24B7321304991100128FB9DCF6 + 506BBF5BD5B802964C636B258E54867BA5C387908A598CDDEA72061B5F3E5315 + 471DD8E93E0EDE7DC45924EFD309E074DBE63AFA3D50B80C3D914164FDCC8825 + D8A4AC604600502A02C5738C5777DD0EDD7DEE9514AD0A2C7A80FD0F9BE0BA89 + D63E37344B9C16621E4D98130A1D51986F01CA04289169A53CFCD5ED95E196A7 + BDD0640758220A295F806CC012EF6D9C211637038A8269CB180BD0F33B3201B0 + EE45F86AEF55CCB60D744021217279B0740EBB6B0944636C94C4737F63118055 + 273DF0ABA8C8309FCB639F6D7FD20245A7855C810017D8FD92C6CF241F953801 + E8B5F94723ADD6DF10FBC9B0701B1926CECCCE32405E87526428A78AD8FD5EC6 + 4901018563FA1F80C8D9E9B185DAFA3C92884A4FA410D94852F798E86CD0A015 + 4CE8E706B6D3E0511313B493A94B80441D36E674DB83E4B67AE9F6DEBA65984F + F451A30373DD0E40CBD28FA8B9B6097B0A4CCAA018576A3040EDB9DCE5BD0799 + ABD0E356544634CE26C8B019EA799419C61A65847A18544DEC966A832A057805 + A0D96697E7DB7BEB872A1D32226B09331A3727AD9CE9120046454336DEC411A4 + D064DA08B680454A7F44FA546B45586FB761C1AE4A83C90C0F9078FAD2D84B00 + 4D201887BF0E089370290F0CAB6298048051DE659DC699A15B96B17C7D7CAF03 + 44D1A75E05D8A1168889F55F525F839E0094AAF50000000049454E44AE426082} + end + end + object chkUseFilenames: TCheckBox + Left = 341 + Top = 7 + Width = 112 + Height = 17 + Anchors = [akTop, akRight] + Caption = 'Use Filenames' + Checked = True + State = cbChecked + TabOrder = 1 + end + end + object dlgOpenPicture: TOpenPictureDialog + DefaultExt = 'png' + Filter = 'Portable Network Graphics (*.png)|*.png' + Options = [ofHideReadOnly, ofPathMustExist, ofFileMustExist, ofEnableSizing] + Title = 'Browse for a PNG file' + Left = 40 + Top = 251 + end + object dlgColor: TColorDialog + Options = [cdAnyColor] + Left = 72 + Top = 251 + end + object Images: TPngImageCollection + Items = <> + Left = 8 + Top = 251 + end +end diff --git a/internal/1.2.0/1/Design/PngImageListEditor.pas b/internal/1.2.0/1/Design/PngImageListEditor.pas new file mode 100644 index 0000000..48137ee --- /dev/null +++ b/internal/1.2.0/1/Design/PngImageListEditor.pas @@ -0,0 +1,1216 @@ +unit PngImageListEditor; + +interface + +uses + Windows, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, + ExtDlgs, pngimage, PngFunctions, PngBitBtn, PngImageList, Buttons; + +type + TPngImageListEditorDlg = class(TForm) + cmbBackgroundColor: TComboBox; + cmbPreviewBackground: TComboBox; + dlgColor: TColorDialog; + dlgOpenPicture: TOpenPictureDialog; + edtName: TEdit; + gbxImageInfo: TGroupBox; + gbxProperties: TGroupBox; + lblBackgroundColor: TLabel; + lblColorDepth: TLabel; + lblColorDepthValue: TLabel; + lblCompression: TLabel; + lblCompressionValue: TLabel; + lblDimensions: TLabel; + lblDimensionsValue: TLabel; + lblFiltering: TLabel; + lblFilteringValue: TLabel; + lblName: TLabel; + lblTransparency: TLabel; + lblTransparencyValue: TLabel; + lbxImages: TListBox; + pnlActionButtons: TPanel; + pnlBackgroundColor: TPanel; + pnlMain: TPanel; + btnAdd: TPngBitBtn; + btnDelete: TPngBitBtn; + btnReplace: TPngBitBtn; + btnClear: TPngBitBtn; + btnUp: TPngBitBtn; + btnDown: TPngBitBtn; + Images: TPngImageCollection; + pnlButtons: TPanel; + pnlModalButtons: TPanel; + btnOK: TPngBitBtn; + btnCancel: TPngBitBtn; + chkUseFilenames: TCheckBox; + procedure btnAddClick(Sender: TObject); + procedure btnClearClick(Sender: TObject); + procedure btnDeleteClick(Sender: TObject); + procedure btnDownClick(Sender: TObject); + procedure btnReplaceClick(Sender: TObject); + procedure btnUpClick(Sender: TObject); + procedure cmbBackgroundColorChange(Sender: TObject); + procedure cmbBackgroundColorDblClick(Sender: TObject); + procedure cmbBackgroundColorExit(Sender: TObject); + procedure cmbPreviewBackgroundChange(Sender: TObject); + procedure cmbPreviewBackgroundDrawItem(Control: TWinControl; Index: Integer; + ARect: TRect; State: TOwnerDrawState); + procedure edtNameChange(Sender: TObject); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + procedure FormCreate(Sender: TObject); + procedure FormResize(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure lbxImagesClick(Sender: TObject); + procedure lbxImagesDblClick(Sender: TObject); + procedure lbxImagesDragOver(Sender, Source: TObject; X, Y: Integer; + State: TDragState; var Accept: Boolean); + procedure lbxImagesDrawItem(Control: TWinControl; Index: Integer; + ARect: TRect; State: TOwnerDrawState); + procedure lbxImagesEnter(Sender: TObject); + procedure lbxImagesExit(Sender: TObject); + procedure lbxImagesKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure lbxImagesMeasureItem(Control: TWinControl; Index: Integer; var Height: Integer); + procedure lbxImagesMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + procedure lbxImagesStartDrag(Sender: TObject; var DragObject: TDragObject); + private + FDraggingIndex: Integer; + FImageHeight: Integer; + FImageWidth: Integer; + FMaxWidth: Integer; + FSelectionBodyColor: TColor; + FSelectionBorderColor: TColor; + function ConformDimensions(Png: TPngImage): Boolean; + function FirstSelected: Integer; + function LastSelected: Integer; + procedure DrawBackground(Canvas: TCanvas; const ARect: TRect; ScrollPos, Index: Integer; + BlendColor: TColor = clNone; IgnoreScrollPos: Boolean = False); + procedure GetColorProc(const S: string); + procedure ParseBackgroundColor(Sender: TObject; CanDisplayError, CanChangeText: Boolean); + procedure SelectBackgroundColor(Sender: TObject; Color: TColor); + public + property ImageHeight: Integer read FImageHeight write FImageHeight; + property ImageWidth: Integer read FImageWidth write FImageWidth; + end; + +var + PngImageListEditorDlg: TPngImageListEditorDlg; + +implementation + +uses + SysUtils, Math; + +resourcestring + SAreYouSureYouWantToDelete = 'Are you sure you want to delete %s?'; + SAnd = ' and '; + SThisWillClearTheEntireImageList = 'This will clear the entire image list. Are you sure you want to do this?'; + SIsNotAValidColorValue = '"%s" is not a valid color value'; + +{$R *.dfm} + +//For calculating OfficeXP colors +const + WeightR: single = 0.764706; + WeightG: single = 1.52941; + WeightB: single = 0.254902; + +const + SIncorrectSize = + 'The selected PNG "%s" must be %dx%d in size, while its actual size is %dx%d'; + +var + ResX, ResY: Integer; + + { Globals } + +function Blend(C1, C2: TColor; W1: Integer): TColor; +var + W2, A1, A2, D, F, G: Integer; +begin + if C1 < 0 then + C1 := GetSysColor(C1 and $FF); + if C2 < 0 then + C2 := GetSysColor(C2 and $FF); + + if W1 >= 100 then + D := 1000 + else + D := 100; + + W2 := D - W1; + F := D div 2; + + A2 := C2 shr 16 * W2; + A1 := C1 shr 16 * W1; + G := (A1 + A2 + F) div D and $FF; + Result := G shl 16; + + A2 := (C2 shr 8 and $FF) * W2; + A1 := (C1 shr 8 and $FF) * W1; + G := (A1 + A2 + F) div D and $FF; + Result := Result or G shl 8; + + A2 := (C2 and $FF) * W2; + A1 := (C1 and $FF) * W1; + G := (A1 + A2 + F) div D and $FF; + Result := Result or G; +end; + +function ColorDistance(C1, C2: Integer): Single; +var + DR, DG, DB: Integer; +begin + DR := (C1 and $FF) - (C2 and $FF); + Result := Sqr(DR * WeightR); + DG := (C1 shr 8 and $FF) - (C2 shr 8 and $FF); + Result := Result + Sqr(DG * WeightG); + DB := (C1 shr 16) - (C2 shr 16); + Result := Result + Sqr(DB * WeightB); + Result := Sqrt(Result); +end; + +function GetAdjustedThreshold(BkgndIntensity, Threshold: Single): Single; +begin + if BkgndIntensity < 220 then + Result := (2 - BkgndIntensity / 220) * Threshold + else + Result := Threshold; +end; + +function IsContrastEnough(AColor, ABkgndColor: Integer; DoAdjustThreshold: Boolean; Threshold: Single): Boolean; +begin + if DoAdjustThreshold then + Threshold := GetAdjustedThreshold(ColorDistance(ABkgndColor, $000000), + Threshold); + Result := ColorDistance(ABkgndColor, AColor) > Threshold; +end; + +procedure AdjustContrast(var AColor: Integer; ABkgndColor: Integer; Threshold: Single); +var + X, Y, Z: Single; + R, G, B: Single; + RR, GG, BB: Integer; + I1, I2, S, Q, W: Single; + DoInvert: Boolean; +begin + I1 := ColorDistance(AColor, $000000); + I2 := ColorDistance(ABkgndColor, $000000); + Threshold := GetAdjustedThreshold(I2, Threshold); + + if I1 > I2 then + DoInvert := I2 < 442 - Threshold + else + DoInvert := I2 < Threshold; + + X := (ABkgndColor and $FF) * WeightR; + Y := (ABkgndColor shr 8 and $FF) * WeightG; + Z := (ABkgndColor shr 16) * WeightB; + + R := (AColor and $FF) * WeightR; + G := (AColor shr 8 and $FF) * WeightG; + B := (AColor shr 16) * WeightB; + + if DoInvert then begin + R := 195 - R; + G := 390 - G; + B := 65 - B; + X := 195 - X; + Y := 390 - Y; + Z := 65 - Z; + end; + + S := Sqrt(Sqr(B) + Sqr(G) + Sqr(R)); + if S < 0.01 then + S := 0.01; + + Q := (R * X + G * Y + B * Z) / S; + + X := Q / S * R - X; + Y := Q / S * G - Y; + Z := Q / S * B - Z; + + W := Sqrt(Sqr(Threshold) - Sqr(X) - Sqr(Y) - Sqr(Z)); + + R := (Q - W) * R / S; + G := (Q - W) * G / S; + B := (Q - W) * B / S; + + if DoInvert then begin + R := 195 - R; + G := 390 - G; + B := 65 - B; + end; + + if R < 0 then + R := 0 + else if R > 195 then + R := 195; + if G < 0 then + G := 0 + else if G > 390 then + G := 390; + if B < 0 then + B := 0 + else if B > 65 then + B := 65; + + RR := Trunc(R * (1 / WeightR) + 0.5); + GG := Trunc(G * (1 / WeightG) + 0.5); + BB := Trunc(B * (1 / WeightB) + 0.5); + + if RR > $FF then + RR := $FF + else if RR < 0 then + RR := 0; + if GG > $FF then + GG := $FF + else if GG < 0 then + GG := 0; + if BB > $FF then + BB := $FF + else if BB < 0 then + BB := 0; + + AColor := (BB and $FF) shl 16 or (GG and $FF) shl 8 or (RR and $FF); +end; + +procedure SetContrast(var Color: TColor; BkgndColor: TColor; Threshold: Integer); +var + T: Single; +begin + if Color < 0 then + Color := GetSysColor(Color and $FF); + if BkgndColor < 0 then + BkgndColor := GetSysColor(BkgndColor and $FF); + T := Threshold; + if not IsContrastEnough(Color, BkgndColor, True, T) then + AdjustContrast(Integer(Color), BkgndColor, T); +end; + +function ResizeProportionalX(InitialValue: Integer): Integer; +begin + Result := InitialValue * ResX div 96; +end; + +function ResizeProportionalY(InitialValue: Integer): Integer; +begin + Result := InitialValue * ResY div 96; +end; + +procedure InitResolution; +var + DC: HDC; +begin + DC := GetDC(0); + ResX := GetDeviceCaps(DC, LOGPIXELSX); + ResY := GetDeviceCaps(DC, LOGPIXELSY); + ReleaseDC(0, DC); +end; + +{ TPngImageListEditorDlg } + +function TPngImageListEditorDlg.ConformDimensions(Png: TPngImage): Boolean; +begin + //Returns whether an image conforms the specified dimensions, if available + Result := ((ImageHeight = 0) and (ImageWidth = 0)) or ((ImageHeight = + Png.Height) and (ImageWidth = Png.Width)); +end; + +function TPngImageListEditorDlg.FirstSelected: Integer; +begin + //Return the first selected image + Result := 0; + while not lbxImages.Selected[Result] and (Result < lbxImages.Items.Count) do + Inc(Result); +end; + +function TPngImageListEditorDlg.LastSelected: Integer; +begin + //Return the last selected image + Result := lbxImages.Items.Count - 1; + while not lbxImages.Selected[Result] and (Result >= 0) do + Dec(Result); +end; + +procedure TPngImageListEditorDlg.DrawBackground(Canvas: TCanvas; const ARect: TRect; + ScrollPos, Index: Integer; BlendColor: TColor; IgnoreScrollPos: Boolean); +var + I, X, Y: Integer; + PatBitmap, BkBitmap: TBitmap; + Even: Boolean; +begin + //Draw the background of the listbox, if any + if Index = 0 then begin + //No background, then skip the hard part + if BlendColor = clNone then + Canvas.Brush.Color := clWindow + else + Canvas.Brush.Color := BlendColor; + Canvas.FillRect(ARect); + Exit; + end; + + //Draw the background + BkBitmap := TBitmap.Create; + PatBitmap := TBitmap.Create; + try + PatBitmap.Height := 16; + PatBitmap.Width := 16; + with PatBitmap.Canvas do begin + //First, draw the background for the pattern bitmap + if BlendColor = clNone then begin + Brush.Color := clWindow; + FillRect(Rect(0, 0, PatBitmap.Height, PatBitmap.Width)); + Brush.Color := Blend(clWindow, clBtnFace, 50); + end + else begin + Brush.Color := Blend(clWindow, BlendColor, 50); + FillRect(Rect(0, 0, PatBitmap.Height, PatBitmap.Width)); + Brush.Color := BlendColor; + end; + + //Then, draw the foreground on the pattern bitmap + Pen.Color := Brush.Color; + case Index of + 1: begin + //Checkerboard background + FillRect(Rect(PatBitmap.Width div 2, 0, PatBitmap.Width, PatBitmap.Height div 2)); + FillRect(Rect(0, PatBitmap.Height div 2, PatBitmap.Width div 2, PatBitmap.Height)); + end; + 2: begin + //Diamonds background + PatBitmap.Width := 10; + PatBitmap.Height := 10; + Polygon([Point(PatBitmap.Width div 2, 0), Point(PatBitmap.Width, + PatBitmap.Height div 2), Point(PatBitmap.Width div 2, + PatBitmap.Height), Point(0, PatBitmap.Height div 2)]); + end; + 3: begin + //Slashed background + Even := True; + I := 2; + while I < PatBitmap.Width + PatBitmap.Height do begin + if I < PatBitmap.Width then begin + MoveTo(I, 0); + LineTo(-1, I + 1); + end + else begin + MoveTo(PatBitmap.Width, I - PatBitmap.Width); + LineTo(I - PatBitmap.Width, PatBitmap.Height); + end; + if Even then + Inc(I, 1) + else + Inc(I, 3); + Even := not Even; + end; + end; + 4: begin + //Backslashed background + Even := True; + I := 2; + while I < PatBitmap.Width + PatBitmap.Height do begin + if I < PatBitmap.Width then begin + MoveTo(I, 0); + LineTo(PatBitmap.Width, PatBitmap.Height - I); + end + else begin + MoveTo(0, I - PatBitmap.Width - 1); + LineTo(PatBitmap.Width - (I - PatBitmap.Width) + 1, + PatBitmap.Height); + end; + if Even then + Inc(I, 1) + else + Inc(I, 3); + Even := not Even; + end; + end; + end; + end; + + //The actual background bitmap, its width and height are increased to compensate + //for scrolling distance + BkBitmap.Width := ARect.Left mod PatBitmap.Width + ARect.Right - ARect.Left; + if IgnoreScrollPos then + ScrollPos := 0 + else + ScrollPos := (ARect.Top + ScrollPos) mod PatBitmap.Height; + BkBitmap.Height := ScrollPos + ARect.Bottom - ARect.Top; + + //Now repeat the pattern bitmap onto the background bitmap + with BkBitmap.Canvas do begin + Y := 0; + while Y < BkBitmap.Height do begin + X := 0; + while X < BkBitmap.Width do begin + Draw(X, Y, PatBitmap); + Inc(X, PatBitmap.Width); + end; + Inc(Y, PatBitmap.Height); + end; + end; + + //And finally, draw the background bitmap to the canvas + BitBlt(Canvas.Handle, ARect.Left, ARect.Top, ARect.Right - ARect.Left, + ARect.Bottom - ARect.Top, BkBitmap.Canvas.Handle, ARect.Left mod + PatBitmap.Width, ScrollPos, SRCCOPY); + finally + BkBitmap.Free; + PatBitmap.Free; + end; +end; + +//Method for getting color values + +procedure TPngImageListEditorDlg.GetColorProc(const S: string); +begin + cmbBackgroundColor.Items.Add(S); +end; + +//Parse a background color name or code + +procedure TPngImageListEditorDlg.ParseBackgroundColor(Sender: TObject; CanDisplayError, CanChangeText: Boolean); +var + S: string; + I, ParsedColor: Integer; +begin + with cmbBackgroundColor do begin + //First, see if its a known color name + if IdentToColor(Text, ParsedColor) then begin + ItemIndex := Items.IndexOf(Text); + pnlBackgroundColor.Color := ParsedColor; + end + else begin + S := Text; + //Replace # with $ so StringToColor recognizes it + if (Length(S) > 0) and (S[1] = '#') then + S[1] := '$'; + try + //Try to convert to a real color value + ParsedColor := StringToColor(S); + if CanChangeText then begin + //And try to convert back to an identifier (i.e. if you type in $000000, it'll become clBlack) + if ColorToIdent(ParsedColor, S) then + ItemIndex := Items.IndexOf(S) + else + Text := S; + end; + pnlBackgroundColor.Color := ParsedColor; + except + //If it fails, display a message if neccesary + on EConvertError do + if CanDisplayError then begin + MessageBox(Self.Handle, + PChar(Format(SIsNotAValidColorValue, [Text])), + PChar(Self.Caption), MB_ICONERROR or MB_OK); + SetFocus; + end; + end; + end; + end; + //And finally, set the background color to every selected image + if (Sender <> lbxImages) then + for I := 0 to lbxImages.Items.Count - 1 do + if lbxImages.Selected[I] then + Images.Items[I].Background := pnlBackgroundColor.Color; +end; + +procedure TPngImageListEditorDlg.SelectBackgroundColor(Sender: TObject; Color: TColor); +var + S: string; +begin + //This happens after a background color has been slected from the color dialog + //Try to convert a color into an identifier, or else into a hexadecimal representation + if ColorToIdent(Color, S) then + cmbBackgroundColor.ItemIndex := cmbBackgroundColor.Items.IndexOf(S) + else + cmbBackgroundColor.Text := '$' + IntToHex(dlgColor.Color, 6); + ParseBackgroundColor(Sender, False, True); +end; + +procedure TPngImageListEditorDlg.btnAddClick(Sender: TObject); +var + Png: TPngImageCollectionItem; + I, Selected, FirstSelected: Integer; +begin + //The Add button is pressed, let the programmer look for an image + dlgOpenPicture.Options := dlgOpenPicture.Options + [ofAllowMultiSelect]; + if dlgOpenPicture.Execute then begin + for I := 0 to lbxImages.Items.Count - 1 do + lbxImages.Selected[I] := False; + FirstSelected := -1; + for I := 0 to dlgOpenPicture.Files.Count - 1 do begin + Png := Images.Items.Add; + with Png.PngImage do begin + //Load the image, but remove any gamma, so that the gamma won't be reapplied + //when loading the image from the DFM + LoadFromFile(dlgOpenPicture.Files[I]); + if Png.PngImage.Header.ColorType in [COLOR_RGB, COLOR_RGBALPHA, + COLOR_PALETTE] then + Chunks.RemoveChunk(Chunks.ItemFromClass(TChunkgAMA)); + end; + //Does the image conform the specified dimensions, if any? + if ConformDimensions(Png.PngImage) then begin + //Update maximum image width + if FMaxWidth < Png.PngImage.Width then + FMaxWidth := Png.PngImage.Width; + + //Invent a name for the image, and initialize its background color + if chkUseFilenames.Checked then + Png.Name := ChangeFileExt(ExtractFileName(dlgOpenPicture.Files[I]), '') + else + Png.Name := 'PngImage' + IntToStr(Images.Items.Count - 1); // do not localize + Png.Background := clWindow; + + //Finally, add it and select it + Selected := lbxImages.Items.AddObject(Png.Name, Png); + lbxImages.Selected[Selected] := True; + if FirstSelected = -1 then + FirstSelected := Selected; + end + else begin + //The image does not conform the specified dimensions + MessageBox(Handle, PChar(Format(SIncorrectSize, + [ExtractFilename(dlgOpenPicture.Files[I]), ImageWidth, ImageHeight, + Png.PngImage.Width, Png.PngImage.Height])), PChar(Caption), MB_ICONERROR or MB_OK); + Images.Items.Delete(Png.Index); + end; + end; + + //Focus the first selected (added) image + lbxImages.ItemIndex := FirstSelected; + lbxImages.SetFocus; + lbxImagesClick(nil); + end; +end; + +procedure TPngImageListEditorDlg.btnClearClick(Sender: TObject); +begin + //Clear the listbox and the collection + if (lbxImages.Items.Count > 0) and (MessageBox(Handle, + PChar(SThisWillClearTheEntireImageList), + PChar(Self.Caption), MB_ICONEXCLAMATION or MB_YESNO or MB_DEFBUTTON2) = + IDYES) then begin + lbxImages.Items.Clear; + Images.Items.Clear; + lbxImagesClick(nil); + end; +end; + +procedure TPngImageListEditorDlg.btnDeleteClick(Sender: TObject); + + function GetCommaList: string; + var + I: Integer; + S: TStringList; + begin + //Get a comma list of the names of the selected images in the form "name1, + //name2 and name3" + Result := ''; + S := TStringList.Create; + try + for I := 0 to lbxImages.Items.Count - 1 do + if lbxImages.Selected[I] then + S.Add(Images.Items[I].Name); + for I := 0 to S.Count - 1 do begin + Result := Result + S[I]; + if I < S.Count - 2 then + Result := Result + ', ' + else if I < S.Count - 1 then + Result := Result + SAnd; + end; + finally + S.Free; + end; + end; + +var + I, NewIndex: Integer; +begin + with lbxImages do + if (SelCount > 0) and (MessageBox(Handle, + PChar(Format(SAreYouSureYouWantToDelete, [GetCommaList])), + PChar(Self.Caption), MB_ICONEXCLAMATION or MB_YESNO) = IDYES) then begin + //Delete every selected image from the listbox and from the collection + NewIndex := -1; + I := 0; + while I < Items.Count do + if Selected[I] then begin + if NewIndex = -1 then + NewIndex := I; + lbxImages.Items.Delete(I); + Images.Items.Delete(I); + end + else + Inc(I); + + //Figure out the new selection index + if NewIndex > Items.Count - 1 then + NewIndex := Items.Count - 1 + else if (NewIndex = -1) and (Items.Count > 0) then + NewIndex := 0; + Selected[NewIndex] := True; + ItemIndex := NewIndex; + lbxImagesClick(nil); + end; +end; + +procedure TPngImageListEditorDlg.btnDownClick(Sender: TObject); +var + I: Integer; +begin + //Move the selected items one position down + with lbxImages do + if (SelCount > 0) and (LastSelected < Items.Count - 1) then + for I := Items.Count - 1 downto 0 do + if Selected[I] then begin + Images.Items[I].Index := I + 1; + Items.Exchange(I, I + 1); + Selected[I + 1] := True; + end; + lbxImagesClick(nil); +end; + +procedure TPngImageListEditorDlg.btnReplaceClick(Sender: TObject); +var + Item: TPngImageCollectionItem; + Index: Integer; + Png: TPngImage; +begin + //The Replace button is pressed, let the programmer look for an image + Index := FirstSelected; + Item := Images.Items[Index]; + dlgOpenPicture.FileName := Item.Name; + dlgOpenPicture.Options := dlgOpenPicture.Options - [ofAllowMultiSelect]; + with lbxImages do + if (SelCount = 1) and dlgOpenPicture.Execute then begin + Png := TPngImage.Create; + try + //First see if the image conforms the specified dimensions + Png.LoadFromFile(dlgOpenPicture.Filename); + if ConformDimensions(Png) then begin + //Then remove any gamma, so that the gamma won't be reapplied when loading the + //image from the DFM + if Png.Header.ColorType in [COLOR_RGB, COLOR_RGBALPHA] then + Png.Chunks.RemoveChunk(Png.Chunks.ItemFromClass(TChunkgAMA)); + Item.PngImage := Png; + + //Update the maximum image width + if FMaxWidth < Item.PngImage.Width then + FMaxWidth := Item.PngImage.Width; + + //Repaint and update everything, to be sure + lbxImages.Repaint; + lbxImagesClick(nil); + end + else + MessageBox(Handle, PChar(Format(SIncorrectSize, + [ExtractFilename(dlgOpenPicture.Filename), ImageWidth, ImageHeight, + Png.Width, Png.Height])), PChar(Caption), MB_ICONERROR or MB_OK); + finally + Png.Free; + end; + end; +end; + +procedure TPngImageListEditorDlg.btnUpClick(Sender: TObject); +var + I: Integer; +begin + //Move the selected items one position up + with lbxImages do + if (SelCount > 0) and (FirstSelected > 0) then + for I := 0 to Items.Count - 1 do + if Selected[I] then begin + Images.Items[I].Index := I - 1; + Items.Exchange(I, I - 1); + Selected[I - 1] := True; + end; + lbxImagesClick(nil); +end; + +procedure TPngImageListEditorDlg.cmbBackgroundColorChange(Sender: TObject); +begin + //While typing, try parsing the background color, but without any error messages + ParseBackgroundColor(Sender, False, False); +end; + +procedure TPngImageListEditorDlg.cmbBackgroundColorDblClick(Sender: TObject); +begin + //Just like in Delphi, when doubleclicking a color, the color dialog pops up + dlgColor.Color := pnlBackgroundColor.Color; + if dlgColor.Execute then + SelectBackgroundColor(Sender, dlgColor.Color); +end; + +procedure TPngImageListEditorDlg.cmbBackgroundColorExit(Sender: TObject); +begin + //When leaving the background combobox, parse the color, but this with error + //message, if neccesary + ParseBackgroundColor(Sender, True, True); +end; + +procedure TPngImageListEditorDlg.cmbPreviewBackgroundChange(Sender: TObject); +begin + //Pewview background is changes, repaint all items + lbxImages.Repaint; +end; + +procedure TPngImageListEditorDlg.cmbPreviewBackgroundDrawItem(Control: TWinControl; + Index: Integer; ARect: TRect; State: TOwnerDrawState); +var + IconWidth: Integer; +begin + with cmbPreviewBackground do begin + //Draw the background "icon" of the preview background combobox + IconWidth := (ARect.Bottom - ARect.Top) * 4 div 3; + DrawBackground(Canvas, Rect(ARect.Left, ARect.Top, ARect.Left + IconWidth, ARect.Bottom), + 0, Index, clNone, True); + Inc(ARect.Left, IconWidth); + + //Background color of the rest of the item + if odSelected in State then + Canvas.Brush.Color := clHighlight + else + Canvas.Brush.Color := clWindow; + Canvas.FillRect(ARect); + Inc(ARect.Left, 4); + + //And the text + DrawText(Canvas.Handle, PChar(Items[Index]), -1, ARect, DT_LEFT or DT_NOPREFIX + or DT_SINGLELINE or DT_VCENTER); + + Canvas.Brush.Color := clWindow; + end; +end; + +procedure TPngImageListEditorDlg.edtNameChange(Sender: TObject); +begin + //Update the selected image with the entered name, in realtime + with lbxImages do + if ItemIndex >= 0 then begin + Images.Items[ItemIndex].Name := edtName.Text; + Items[ItemIndex] := edtName.Text; + end; +end; + +procedure TPngImageListEditorDlg.FormClose(Sender: TObject; var Action: TCloseAction); +begin + Action := caFree; +end; + +procedure TPngImageListEditorDlg.FormCreate(Sender: TObject); +var + Space8H: Integer; +begin + //Initialize OfficeXP colors for selection + FSelectionBodyColor := Blend(clHighlight, clWindow, 30); + SetContrast(FSelectionBodyColor, Blend(clWindow, clBtnFace, 165), 50); + FSelectionBorderColor := clHighlight; + + //Initialize a value that keeps track of dragging + FDraggingIndex := -1; + + //Get all available color names + GetColorValues(GetColorProc); + + //Initialize the background to clWindow + cmbBackgroundColor.ItemIndex := cmbBackgroundColor.Items.IndexOf('clWindow'); // do not localize + cmbBackgroundColorChange(nil); + + //Do not specify image width and height by default (the imagelist will fill + //these up, so that you cannot select an image other than these dimensions) + ImageWidth := 0; + ImageHeight := 0; + + //Resize everything to make it fit on "large fonts" setting. Note that these + //operations are also needed on normal setting. + Space8H := lbxImages.Top; + Width := ResizeProportionalX(Width); + Height := ResizeProportionalY(Height); + Constraints.MinHeight := gbxProperties.Top + cmbBackgroundColor.Top + + cmbBackgroundColor.Height + Space8H + Space8H + gbxImageInfo.Height + Space8H + + (Height - pnlMain.Height); + Constraints.MinWidth := Width; + pnlButtons.Align := alBottom; + pnlMain.Align := alClient; + cmbPreviewBackground.ItemHeight := + ResizeProportionalY(cmbPreviewBackground.ItemHeight); + pnlBackgroundColor.Height := cmbBackgroundColor.Height; + + //Make sure the background color isn't reset when themes are enabled + pnlBackgroundColor.ParentBackground := True; + pnlBackgroundColor.ParentBackground := False; +end; + +procedure TPngImageListEditorDlg.FormResize(Sender: TObject); +begin + //There appears to be a bug that prevents a listbox from being redrawn correctly + //when the form is resized + lbxImages.Repaint; +end; + +procedure TPngImageListEditorDlg.FormShow(Sender: TObject); +var + I: Integer; +begin + //Initialize the maximum width of the images, to align text in the listbox + FMaxWidth := 0; + for I := 0 to Images.Items.Count - 1 do + if Images.Items[I].PngImage.Width > FMaxWidth then + FMaxWidth := Images.Items[I].PngImage.Width; + + //Fill the listbox with the images + for I := 0 to Images.Items.Count - 1 do + lbxImages.Items.AddObject(Images.Items[I].Name, Images.Items[I]); + if lbxImages.Items.Count > 0 then begin + lbxImages.Selected[0] := True; + lbxImages.ItemIndex := 0; + end; + lbxImages.SetFocus; + lbxImagesClick(nil); + + cmbPreviewBackground.ItemIndex := 0; + FormResize(nil); +end; + +procedure TPngImageListEditorDlg.lbxImagesClick(Sender: TObject); + + function GetDimensions(Png: TPngImage): string; + begin + //Return the formatted dimensions of an image + Result := Format('%dx%d', [Png.Width, Png.Height]); + if Png.InterlaceMethod <> imNone then + Result := Result + ' interlace'; + end; + + function GetColorDepth(Png: TPngImage): string; + begin + //Return the color depth, including whether the image is grayscale or paletted + case Png.Header.ColorType of + COLOR_GRAYSCALE, COLOR_GRAYSCALEALPHA: + Result := Format('%d-bits grayscale', [Png.Header.BitDepth]); + COLOR_RGB, COLOR_RGBALPHA: + Result := Format('%d-bits', [Png.Header.BitDepth * 3]); + COLOR_PALETTE: + Result := Format('%d-bits paletted', [Png.Header.BitDepth]); + end; + end; + + function GetTransparency(Png: TPngImage): string; + begin + //Return the formatted transparency depth, or transparency mode + if Png.Header.ColorType in [COLOR_GRAYSCALEALPHA, COLOR_RGBALPHA] then + Result := Format('%d-bits alpha', [Png.Header.BitDepth]) + else + case Png.TransparencyMode of + ptmBit: Result := 'bitmask'; + ptmPartial: Result := 'indexed'; + else + Result := 'none'; + end; + end; + + function GetCompression(Png: TPngImage): string; + begin + //Return the formatted compression level + Result := Format('level %d', [Png.CompressionLevel]); + end; + + function GetFiltering(Png: TPngImage): string; + begin + //Return the formatted filtering method + case Png.Header.FilterMethod of + FILTER_SUB: Result := 'sub'; + FILTER_UP: Result := 'up'; + FILTER_AVERAGE: Result := 'average'; + FILTER_PAETH: Result := 'paeth'; + else + Result := 'none'; + end; + end; + + function SameBackgroundColor: Boolean; + var + FirstBgColor: TColor; + I: Integer; + First: Boolean; + begin + //Determine whether the background color of all selected images is the same + FirstBgColor := clNone; + First := True; + Result := True; + for I := 0 to lbxImages.Items.Count - 1 do + if lbxImages.Selected[I] then + if First then begin + //Found the first selected and its background color + FirstBgColor := Images.Items[I].Background; + First := False; + end + else begin + //If not equal to first background color, then break, continue otherwise + Result := FirstBgColor = Images.Items[I].Background; + if not Result then + Break; + end; + end; + +const + NoneSelected = '[ none ]'; + MultipleSelected = '[ multiple ]'; +begin + with lbxImages do begin + //Refresh the enabled state of the buttons and controls + btnReplace.Enabled := SelCount = 1; + btnDelete.Enabled := SelCount > 0; + btnClear.Enabled := Items.Count > 0; + btnUp.Enabled := (SelCount > 0) and (FirstSelected > 0); + btnDown.Enabled := (SelCount > 0) and (LastSelected < Items.Count - 1); + lblName.Enabled := SelCount = 1; + edtName.Enabled := SelCount = 1; + lblBackgroundColor.Enabled := SelCount > 0; + cmbBackgroundColor.Enabled := SelCount > 0; + case SelCount of + 0: begin + //None is selected, so no information to display + lblDimensionsValue.Caption := NoneSelected; + lblColorDepthValue.Caption := NoneSelected; + lblTransparencyValue.Caption := NoneSelected; + lblCompressionValue.Caption := NoneSelected; + lblFilteringValue.Caption := NoneSelected; + end; + 1: with Images.Items[FirstSelected] do begin + edtName.OnChange := nil; + try + //One item is selected, display its properties and information + edtName.Text := Name; + SelectBackgroundColor(Sender, Background); + lblDimensionsValue.Caption := GetDimensions(PngImage); + lblColorDepthValue.Caption := GetColorDepth(PngImage); + lblTransparencyValue.Caption := GetTransparency(PngImage); + lblCompressionValue.Caption := GetCompression(PngImage); + lblFilteringValue.Caption := GetFiltering(PngImage); + finally + edtName.OnChange := edtNameChange; + end; + end; + else begin + //More than 1 is selected, so no image information can be displayed + if SameBackgroundColor then + SelectBackgroundColor(Sender, Images.Items[FirstSelected].Background) + else + SelectBackgroundColor(Sender, clNone); + lblDimensionsValue.Caption := MultipleSelected; + lblColorDepthValue.Caption := MultipleSelected; + lblTransparencyValue.Caption := MultipleSelected; + lblCompressionValue.Caption := MultipleSelected; + lblFilteringValue.Caption := MultipleSelected; + end; + end; + end; +end; + +procedure TPngImageListEditorDlg.lbxImagesDblClick(Sender: TObject); +begin + //Doubleclicking is the same as the Replace button + if lbxImages.SelCount = 1 then + btnReplaceClick(nil); +end; + +procedure TPngImageListEditorDlg.lbxImagesDragOver(Sender, Source: TObject; + X, Y: Integer; State: TDragState; var Accept: Boolean); + + procedure MoveItem(Index, Delta: Integer); + begin + //Move a single item up or down, depending on Delta + if lbxImages.Selected[Index] then begin + Images.Items[Index].Index := Index + Delta; + lbxImages.Items.Exchange(Index, Index + Delta); + lbxImages.Selected[Index + Delta] := True; + end; + end; + + function InRange(Index: Integer): Boolean; + begin + //Return whether Index exists in the listbox + Result := (Index >= 0) and (Index < lbxImages.Items.Count); + end; + +var + NewIndex, NewItemIndex, Delta, I: Integer; +begin + Accept := FDraggingIndex >= 0; + if Accept then begin + //Figure out to which index is dragged + NewIndex := lbxImages.ItemAtPos(Point(X, Y), False); + if NewIndex > lbxImages.Items.Count - 1 then + NewIndex := lbxImages.Items.Count - 1; + + //Figure out the distance (delta) of the drag + Delta := NewIndex - FDraggingIndex; + + //The destination index has to exist and has to be differend from where we + //started the drag. On to pof that, the drag destination of the first and + //last selected items have to be in range. + if (NewIndex >= 0) and (NewIndex <> FDraggingIndex) and InRange(FirstSelected + + Delta) and InRange(LastSelected + Delta) then begin + //Calc the new focus index + NewItemIndex := lbxImages.ItemIndex + Delta; + + //To prevent things to get messed up, moving downwards needs walking through the + //images in opposite direction + if Delta < 0 then + for I := 0 to lbxImages.Items.Count - 1 do + MoveItem(I, Delta) + else + for I := lbxImages.Items.Count - 1 downto 0 do + MoveItem(I, Delta); + + //Set the new focus index and tracking value of the drag + lbxImages.ItemIndex := NewItemIndex; + FDraggingIndex := NewIndex; + + lbxImagesClick(nil); + end; + end; +end; + +procedure TPngImageListEditorDlg.lbxImagesDrawItem(Control: TWinControl; Index: Integer; ARect: TRect; State: TOwnerDrawState); +var + DrawRect: TRect; + ScrollInfo: TScrollInfo; + I, ScrollPos: Integer; +begin + //Get the scrolling distance + ScrollPos := 0; + ScrollInfo.cbSize := SizeOf(ScrollInfo); + ScrollInfo.fMask := SIF_POS; + if GetScrollInfo(lbxImages.Handle, SB_VERT, ScrollInfo) then + for I := 0 to ScrollInfo.nPos - 1 do + with lbxImages.ItemRect(I) do + Inc(ScrollPos, Bottom - Top); + + //First, draw the background + if odSelected in State then + if lbxImages.Focused then + DrawBackground(lbxImages.Canvas, ARect, ScrollPos, + cmbPreviewBackground.ItemIndex, FSelectionBodyColor) + else + DrawBackground(lbxImages.Canvas, ARect, ScrollPos, + cmbPreviewBackground.ItemIndex, Blend(FSelectionBodyColor, clWindow, 50)) + else + DrawBackground(lbxImages.Canvas, ARect, ScrollPos, + cmbPreviewBackground.ItemIndex); + with lbxImages.Canvas do begin + //Then, draw a focus border, if focused + Brush.Style := bsClear; + if odFocused in State then begin + if lbxImages.Focused then + Pen.Color := FSelectionBorderColor + else + Pen.Color := Blend(FSelectionBorderColor, clWindow, 50); + Pen.Style := psSolid; + Rectangle(ARect); + end; + + //Draw the image at the center of (ARect.Left, ARect.Top, ARect.Left + FMaxWidth, ARect.Bottom) + with Images.Items[Index] do begin + DrawRect.Left := ARect.Left + (FMaxWidth - PngImage.Width) div 2 + 2; + DrawRect.Top := ARect.Top + (ARect.Bottom - ARect.Top - PngImage.Height) div 2; + DrawRect.Right := DrawRect.Left + PngImage.Width; + DrawRect.Bottom := DrawRect.Top + PngImage.Height; + PngImage.Draw(lbxImages.Canvas, DrawRect); + end; + + //Draw the image index number and the name + Font.Color := clWindowText; + DrawRect := Rect(ARect.Left + FMaxWidth + 8, ARect.Top, ARect.Left + + FMaxWidth + Canvas.TextWidth(IntToStr(lbxImages.Items.Count - 1)) + 8, + ARect.Bottom); + DrawText(Handle, PChar(IntToStr(Index)), -1, DrawRect, DT_RIGHT or + DT_NOPREFIX or DT_SINGLELINE or DT_VCENTER); + DrawRect.Left := DrawRect.Right; + DrawRect.Right := ARect.Right; + DrawText(Handle, PChar(' - ' + Images.Items[Index].Name), -1, DrawRect, + DT_END_ELLIPSIS or DT_LEFT or DT_NOPREFIX or DT_SINGLELINE or DT_VCENTER); + + //Draw the normal focusrect, so that it'll become invisible + if (odFocused in State) and lbxImages.Focused then + DrawFocusRect(ARect); + end; +end; + +procedure TPngImageListEditorDlg.lbxImagesEnter(Sender: TObject); +begin + //Just to be sure + lbxImages.Repaint; +end; + +procedure TPngImageListEditorDlg.lbxImagesExit(Sender: TObject); +begin + //Just to be sure + lbxImages.Repaint; +end; + +procedure TPngImageListEditorDlg.lbxImagesKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); +begin + //I would expect this "ctrl"-navigation would work standardly, but appearantly + //it doesn't, so we'll have to code it ourselves + with lbxImages do + if ssCtrl in Shift then begin + case Key of + VK_DOWN: begin + if ItemIndex < Items.Count - 1 then + ItemIndex := ItemIndex + 1; + Key := 0; + end; + VK_UP: begin + if ItemIndex > 0 then + ItemIndex := ItemIndex - 1; + Key := 0; + end; + VK_SPACE: begin + Selected[ItemIndex] := not Selected[ItemIndex]; + lbxImagesClick(nil); + Key := 0; + end; + end; + end; +end; + +procedure TPngImageListEditorDlg.lbxImagesMeasureItem(Control: TWinControl; Index: Integer; var Height: Integer); +var + Temp: Integer; +begin + //Figure out the height of an item, when editing an image collection, the height + //of an image may differ + Height := Images.Items[Index].PngImage.Height + 4; + Temp := lbxImages.Canvas.TextHeight('0') + 4; + if Temp > Height then + Height := Temp; +end; + +procedure TPngImageListEditorDlg.lbxImagesMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); +begin + //If the mouse button is released, the tracking value of the drag needs to be + //reset as well + FDraggingIndex := -1; +end; + +procedure TPngImageListEditorDlg.lbxImagesStartDrag(Sender: TObject; var DragObject: TDragObject); +var + Pos: TPoint; +begin + //Figure out where this drag start is + GetCursorPos(Pos); + FDraggingIndex := lbxImages.ItemAtPos(lbxImages.ScreenToClient(Pos), True); + if FDraggingIndex >= 0 then + lbxImages.ItemIndex := FDraggingIndex; +end; + +initialization + InitResolution; + +end. + diff --git a/internal/1.2.0/1/Docs/Changelog.txt b/internal/1.2.0/1/Docs/Changelog.txt new file mode 100644 index 0000000..c046216 --- /dev/null +++ b/internal/1.2.0/1/Docs/Changelog.txt @@ -0,0 +1,45 @@ +PngComponents 1.1: +- Common: "adopted" the project from Martijn Saly +- Common: added D2009 support (mostly changed PngObject to PngImage) +- Common: removed compatibility with versions below Delphi 7 +- Common: removed references to Thany.Inc (use RTLVersion instead) +- Common: cleaned up the code (mostly to use my formatting style) +- Editor: added "use file name" in PngImageListEditor (sets the name of the image to it's filename) + +PngComponents 1.0 RC3: +- Editor: Fixed "invalid header" exception when adding a PNG to the list. +- Editor: Everything should now look good on "large fonts" setting. +- PngBitBtn: Positioning and drawing of the glyph was sometimes a bit odd. +- PngBitBtn: Removed the need to draw an empty TBitmap glyph, prior to drawing the PNG glyph. +- PngSpeedButton: The image is now shifted down-right by 1 pixel, when the button is down but not pressed, to match the behavior of a normal SpeedButton. +- PngImageList: Fixed range check errors in PngToIcon32. +- PngImageList: Fixed possible AccessViolation in PngToIcon32. +- PngImageList: Fixed AccessViolation in AddImages. +- PngImageList: Fixed memory leak in CopyPngs. +- PngImageList: Added BeginUpdate and EndUpdate methods, to temporarily prevent the internal imagelist from being updated. +- PngImageList: The patched methods are more efficient, because they now manipulate the internal imagelist directly, rather than relying on CopyPngs. +- PngImageList: Added calls to Change in the patched methods. + +PngComponents 1.0 RC2: +- Editor: Fixed endless loop when repetitively removing the last image in a list of at least 3 (thanks to Aleksander Oven). +- Editor: Fixed possible out-of-bounds error when moving an image down using the Down button (thanks to Spiril). +- Editor: Now using Graphics.GetColorValues to retrieve available color identifiers (thanks to LJ and Ryan Mills). +- Editor: Rewritten ParseBackgroundColor and SelectBackgroundColor to use IdentToColor, StringToColor and ColorToIdent from Gaphics unit (thanks to LJ and Ryan Mills). +- Editor: It is now possible to set the background color to more than 1 selected image. +- Editor: Minor GUI fixes +- PngBitBtn: When Margin <> -1 and the button is focused, the image must be shifted 1 pixel, to match the behavior of a normal BitBtn. +- PngBitBtn: Fixed EPngHeaderNotPresent when assigning a nil to the PngImage property. +- PngBitBtn: PngImage property now behaves correctly when assigning an action. Note that the image will not be stored in the DFM if it came from a TActionList.ImageList (thanks to robvdl) +- PngSpeedButton: The same fixes that apply to PngBitBtn, applied to PngSpeedButton. +- PngImageList: Adding a default action to an imagelist no longer results in out of bounds errors (thanks to robvdl). +- PngImageList: 14 methods that couldn't be overridden are now patched (thanks to Vladimir Bochkarev). However, adding a default action to an imagelist still doesn't call the "new" Add method, but supposedly the legacy ImageList_Add() function, which cannot be patched. +- PngImageList: Fixed memory leak in CopyPngs (thanks to M. Youssfi). +- Common: Added Amount parameter to MakeImageBlended and MakeImageGrayscale. +- Common: Added function ConvertToPNG, which converts a TGraphic to a PNG object, if not already. +- Common: Added functions CreatePNG and CreatePNGMasked, which create a new PNG object based on a bitmap and a (color or bitmap) mask. +- Common: Added function CopyImageFromImageList, which effectively copies an image from a normal imagelist or a PngImageList into a PNG. +- Common: Added function SlicePNG for future use. This slices a large PNG object into smaller, equally-sized ones. +- Common: Added zlib version 1.2.2 to the PNG package (thanks to Vladimir Bochkarev). + +PngComponents 1.0 RC1: +- Initial public release \ No newline at end of file diff --git a/internal/1.2.0/1/Docs/License.txt b/internal/1.2.0/1/Docs/License.txt new file mode 100644 index 0000000..b279ad4 --- /dev/null +++ b/internal/1.2.0/1/Docs/License.txt @@ -0,0 +1,73 @@ +END-USER LICENSE AGREEMENT + +All files included in this archive are Copyright (C) 2002-2005 Martijn Saly. +Use and/or distribution of them requires acceptance of the following License +Agreement. + +-------------------------------------------------------------------------------- + +- "Author" herein refers to Martijn Saly (the creator of this package and + containing files and software). +- "Software" herein refers to all files bearing this notice, as well as any + other files and source code included with this package (typically extracted + from a .zip or .cab archive), and all content in them, regardless of whether + any modifications have been made. +- "Compile" herein refers to the automatic process of translating the Software's + source code into executable machine code by a compiler such as the one + included with Borland's Delphi or C++Builder. + +Except where otherwise noted, all of the documentation and Software included in +the this package is copyrighted by Martijn Saly (the Author). + +Copyright (C) 2002-2005 Martijn Saly. All rights reserved. + + +Use and distribution of the software is permitted provided that all of the +following terms are accepted. Terms 5 through 8 apply only to distributions +which include source code that one can Compile. + +1) The Software is provided "as-is," without any express or implied warranty. In + no event shall the Author be held liable for any damages arising from the use + or Compile of the Software. + +2) All redistributions of the Software's files must be in their original, + unmodified form. Distributions of modified versions of the files is not + permitted without express written permission of the Author. + +3) All redistributions of the Software's files must retain all copyright notices + and web site addresses that are currently in place, and must include this + list of conditions in its original, unmodified form. + +4) None of the Software's files may be redistributed for profit or as part of + another software package without express written permission of the Author. + +5) If applicable, you are permitted to Compile the Software, in orginal or + modified form, into any kind of application, including commercial or + shareware applications, or any application you are profiting from. + +6) If applicable, redistribution of any of the Software's files in object form + (including but not limited to .DCU and .OBJ formats) is strictly prohibited + without express written permission of the Author. + +7) If applicable, distribution of the Software in compiled package format + (the BPL file) is permitted, as long as the Software is distributed as part + of an application. + +8) If applicable, distribution of the Software in compiled package format + (the BPL file) is prohibed if the distribution does not specifically belong + to an application, written by the same author as the application was written + by. + +9) Full backward compatibility in future versions of the Software is not + guaranteed. In no event shall the Author be held liable for any inconvenience + or damages arising from lack of backward compatibility. + +If you do not agree to all of the above terms, you are not permitted to use or +Compile the Software in any way, and all copies of it must be deleted from your +system(s). + +---------------------------------------------------------------------------- + +Martijn Saly +martijn@thany.org +http://www.thany.org/ \ No newline at end of file diff --git a/internal/1.2.0/1/Docs/PngComponents.html b/internal/1.2.0/1/Docs/PngComponents.html new file mode 100644 index 0000000..1e3922c --- /dev/null +++ b/internal/1.2.0/1/Docs/PngComponents.html @@ -0,0 +1,105 @@ + + +
+This version: 1.0 RC2
+ +PngComponents is a set of components that allows you to include in your application real PNG files. PNG files on their own do not generate an enourmous advantage, but their support for an alpha-channel does indeed have quite a charm to it. The PngComponents library supports alpha-channels to their full extend, using a modified version of the excellent pngdelphi library.
+
+
+
+
+ PngComponents' main and most important component is the PngImageList. This is a descendant of the normal TImageList, with in addition full support for PNGs with an alpha-channel. This will enable you to keep using most components that take advantage of imagelists, while actually feeding them icons with alphablending capabilities. Two other very nice components are the PngSpeedButton and the PngBitBtn. These two buttons do not have a Glyph anymore, but in stead, they accept a PNG file to be assigned directly to the button, without the need for an imagelist (just like the normal SpeedButton and BitBtn). And since the PNG glyphs are drawn in realtime, there's no more hassling with WM_DISPLAYCHANGE when the user changes the clBtnFace color in his display settings...
+Two other components included in the library are the PngImageCollection, which is simply a collection of PNG images. Nothing more, nothing less. The last one is the PngCheckListBox. This one accepts PNG glyphs for the check states. Beside that, it's a completely normal CheckListBox.
+I've also added a "fix" for Alex Desinov's awesome addon for Jordan Russell's Toolbar2000, called TBX. This fix is a replacement for the OfficeXP theme. Just replace TBXOfficeXPTheme in your uses clause with PngTBXOfficeXPTheme and that's it! Beautiful alphablended icons become possible in the OfficeXP theme as well.
+ +The PngComponents library offers a major leap forward in creating nice GUI's in designtime. Not only does it speed up the implementation of alphablended icons in your application, it eases the way you can use them throughout your software. No longer do you need to put them in a resource file manually and then manually drawing them on a temporary bitmap and assigning that to somewhere. Adding beautiful alphablended icons to your interface is but a few clicks away.
+ +The PngBitBtn and PngSpeedButton both have two extra properties, PngImage and PngOptions. PngImage substitutes the Glyph property with a PNG image, so only PNG files can be loaded into it. PngOptions determines what a disabled glyph looks like. You can choose from a combination of having it blended and having it grayscaled.
+The PngImageList and PngImageCollection share the same editor. This editor can be used to load PNG files into the respective component. When editing a PngImageList, the editor will only allow PNG files that have the correct dimensions. When editing a PngImageCollection, any PNG can be added. Note that in either case, it doesn't matter if you mix color depths or other properties.
+Note: the beta versions of PngComponents required that you use a PngImageCollection and assign it to the PngImageList.PngImages property. That is no longer the case, i.o.w. the components have been separated completely.
+ +As said before, the PngImageList and PngImageCollection share an editor that allows to modify the contents of the respective component:
+The editor will show up when you doubleclick the PngImageList or PngImageCollection component. You may also select Edit images... from its context menu, or doubleclick the PngImageList.PngImages or PngImageCollection.Items property.
+ +The ImageList has some features and issues you should probably know about:
+A small introduction: Jordan Russell's Toolbar2000 is a set of components for creating Office 2000-style toolbars and such. Alex Desinov's TBX is an add-on package that adds even more functionality as well as theming. This allows for themes like "OfficeXP", "Office2003" and more.
+The OfficeXP theme comes standard with TBX and it's the one getting in major trouble when using in combination with PngComponents. The alpha-blended area's look ugly, images may show dark borders, and other kinds of artefacts may show up.
+The fix I've included is as simple as it is effective; it's a unit called PngTBXOfficeXPTheme. If you replace TBXOfficeXPTheme in your uses clauses with PngTBXOfficeXPTheme, you should be all set! You will not have the fancy looks in designtime, but in runtime your application will look better than ever.
+Warning! If you still need TBXOfficeXPTheme included in your uses clause, then make sure PngTBXOfficeXPTheme gets initialized after TBXOfficeXPTheme, or it will not work as expected.
+ +I love to get feedback! You can either go to the newsgroup or send me an e-mail if you have a specific question.
+See the License.txt file included in the archive. If the file is not there, the ZIP file is not a genuine PngComponents download!
+ +| This page is best viewed with Opera or Firefox. This page is also optmized for printing. |